您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Reveal hidden timestamps in Claude conversations with robust DOM/API handling, XHR support, and debounced observer; always show year; larger font.
当前为
// ==UserScript== // @name Displays Date & Times within Anthropic Claude Conversations (ES5-safe) // @namespace http://tampermonkey.net/ // @version 2.4 // @license MIT // @description Reveal hidden timestamps in Claude conversations with robust DOM/API handling, XHR support, and debounced observer; always show year; larger font. // @author Wayne // @match https://claude.ai/* // @grant none // @run-at document-end // ==/UserScript== (function () { 'use strict'; var CONFIG = { timestampClass: 'claude-timestamp', messageSelector: "[data-testid*='message'], [class*='message'], .font-claude-message, [role='article']", observerDelay: 500, debounceDelay: 250, timestampFormat: 'absolute', position: 'inline', maxJsonScriptSize: 200000, // no numeric separator timestampFontSizePx: 15 // increased from 12px (~+3pt) }; function formatTimestamp(isoString) { var date = new Date(isoString); return date.toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit', hour12: true, year: 'numeric' }); } function injectStyles() { if (document.getElementById('claude-timestamp-styles')) return; var style = document.createElement('style'); style.id = 'claude-timestamp-styles'; style.textContent = '.' + CONFIG.timestampClass + ' {' + 'font-size: ' + CONFIG.timestampFontSizePx + 'px;' + 'color: #5d6269;' + 'margin-bottom: 6px;' + "font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;" + 'display: block;' + '}' + '@media (prefers-color-scheme: dark) {' + '.' + CONFIG.timestampClass + ' { color: #a2acba; }' + '}'; document.head.appendChild(style); } function extractTimestamp(messageElement) { var dataAttrs = ['data-timestamp', 'data-created-at', 'data-time']; for (var i = 0; i < dataAttrs.length; i++) { var value = messageElement.getAttribute(dataAttrs[i]); if (value) return value; } var parent = messageElement.closest("[data-testid*='conversation'], .conversation, main"); if (parent) { var scripts = parent.querySelectorAll("script[type='application/json']"); for (var j = 0; j < scripts.length; j++) { var txt = scripts[j].textContent || ''; if (txt.length > CONFIG.maxJsonScriptSize) continue; try { var data = JSON.parse(txt); if (data.created_at) return data.created_at; if (data.timestamp) return data.timestamp; } catch (e) {} } } var messageId = messageElement.id || messageElement.getAttribute('data-message-id'); if (messageId && window.conversationData && window.conversationData.messages) { var message = null; for (var m = 0; m < window.conversationData.messages.length; m++) { if (window.conversationData.messages[m].id === messageId) { message = window.conversationData.messages[m]; break; } } if (message && message.created_at) return message.created_at; } var keys = Object.keys(messageElement); var reactKey = null; for (var k = 0; k < keys.length; k++) { if (keys[k].indexOf('__reactFiber$') === 0 || keys[k].indexOf('__reactProps$') === 0 || keys[k].indexOf('__reactInternalInstance') === 0) { reactKey = keys[k]; break; } } if (reactKey) { try { var fiber = messageElement[reactKey]; var props = (fiber && fiber.return && fiber.return.memoizedProps) || (fiber && fiber.memoizedProps) || (fiber && fiber.pendingProps) || (fiber && fiber.return && fiber.return.pendingProps); var ts = (props && props.message && props.message.created_at) || (props && props.timestamp) || (props && props.createdAt); if (ts) return ts; } catch (e) {} } return null; } function interceptNetworkData() { var originalFetch = window.fetch; window.fetch = function () { var args = arguments; var req = args[0]; var url = typeof req === 'string' ? req : (req && req.url ? req.url : ''); return originalFetch.apply(this, args).then(function (res) { if (url && /(\/conversations|\/chat)\b/.test(url)) { try { var clone = res.clone(); var ct = (clone.headers && typeof clone.headers.get === 'function' ? clone.headers.get('content-type') : '') || ''; if (ct.indexOf('application/json') !== -1) { clone.json().then(function (data) { if (data && (data.messages || data.conversation)) { window.conversationData = data; setTimeout(processMessages, 100); } })["catch"](function () {}); } } catch (e) {} } return res; }); }; } function interceptXHR() { var originalOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function (method, url) { this._url = url; return originalOpen.apply(this, arguments); }; var originalSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function () { this.addEventListener('load', function () { if (this._url && /(\/conversations|\/chat)\b/.test(this._url)) { try { var ct = this.getResponseHeader('content-type') || ''; if (ct.indexOf('application/json') !== -1) { var data = JSON.parse(this.responseText); if (data && (data.messages || data.conversation)) { window.conversationData = data; setTimeout(processMessages, 100); } } } catch (e) {} } }); return originalSend.apply(this, arguments); }; } function addTimestamp(messageElement, timestamp) { if (messageElement.querySelector('.' + CONFIG.timestampClass)) return; var timestampElement = document.createElement('div'); timestampElement.className = CONFIG.timestampClass; timestampElement.textContent = formatTimestamp(timestamp); messageElement.insertBefore(timestampElement, messageElement.firstChild); } function debounce(fn, delay) { var timer; return function () { var context = this, args = arguments; clearTimeout(timer); timer = setTimeout(function () { fn.apply(context, args); }, delay); }; } function setupObserver() { var debouncedProcess = debounce(processMessages, CONFIG.debounceDelay); var observer = new MutationObserver(function (mutations) { var shouldProcess = false; for (var i = 0; i < mutations.length; i++) { var mutation = mutations[i]; if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { for (var n = 0; n < mutation.addedNodes.length; n++) { var node = mutation.addedNodes[n]; if (node.nodeType === 1 && ( (node.matches && node.matches(CONFIG.messageSelector)) || (node.querySelector && node.querySelector(CONFIG.messageSelector)) )) { shouldProcess = true; break; } } } if (shouldProcess) break; } if (shouldProcess) debouncedProcess(); }); observer.observe(document.body, { childList: true, subtree: true }); return observer; } function init() { injectStyles(); interceptNetworkData(); interceptXHR(); setTimeout(processMessages, 1000); setupObserver(); setInterval(processMessages, 10000); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { setTimeout(init, 100); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址