Silently prepends a timestamp to every message you send on arena.ai, so the AI knows the current date and time without exposing your timezone.
// ==UserScript==
// @name AI Chat Timestamper
// @namespace https://greasyfork.org/
// @version 1.0
// @description Silently prepends a timestamp to every message you send on arena.ai, so the AI knows the current date and time without exposing your timezone.
// @author NoName
// @license CC0-1.0
// @match *://arena.ai/*
// @match *://*.arena.ai/*
// @match *://lmarena.ai/*
// @match *://*.lmarena.ai/*
// @run-at document-start
// @grant none
// ==/UserScript==
(function () {
'use strict';
function buildTimestampParts() {
const now = new Date();
const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
const pad = n => String(n).padStart(2, '0');
const year = now.getFullYear();
const month = pad(now.getMonth() + 1);
const day = pad(now.getDate());
const dow = days[now.getDay()];
let hour = now.getHours();
const min = pad(now.getMinutes());
const ampm = hour >= 12 ? 'PM' : 'AM';
hour = hour % 12;
if (hour === 0) hour = 12;
const plain = `${year}-${month}-${day} ${dow} ${hour}:${min} ${ampm}`;
const full = `[${plain}] (Auto-generated)`;
return { plain, full };
}
let toastEl = null;
let toastTimer = null;
function showToast(message) {
function render() {
if (!toastEl) {
toastEl = document.createElement('div');
toastEl.id = 'ai-ts-toast';
toastEl.style.cssText = `
position: fixed;
left: 12px;
bottom: 12px;
z-index: 999999;
max-width: 82vw;
padding: 9px 12px;
border-left: 4px solid #22c55e;
border-radius: 10px;
background: #161616;
color: #f5f5f5;
font-size: 12px;
font-family: monospace;
line-height: 1.35;
word-break: break-word;
opacity: 0;
transform: translateY(6px);
transition: opacity 0.14s ease, transform 0.14s ease;
pointer-events: none;
`;
document.body.appendChild(toastEl);
}
toastEl.textContent = `🕐 ${message}`;
toastEl.style.opacity = '1';
toastEl.style.transform = 'translateY(0)';
clearTimeout(toastTimer);
toastTimer = setTimeout(() => {
if (!toastEl) return;
toastEl.style.opacity = '0';
toastEl.style.transform = 'translateY(6px)';
}, 2200);
}
if (document.body) {
render();
} else {
document.addEventListener('DOMContentLoaded', render, { once: true });
}
}
function alreadyStamped(text) {
return /^\[\d{4}-\d{2}-\d{2}\s(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)\s.+?\]\s\(Auto-generated\)/.test(text);
}
function tryStampPayload(parsed, stampText) {
let changed = false;
// Known current shape
if (
parsed &&
parsed.userMessage &&
typeof parsed.userMessage === 'object' &&
typeof parsed.userMessage.content === 'string' &&
!alreadyStamped(parsed.userMessage.content)
) {
parsed.userMessage.content = stampText + '\n\n' + parsed.userMessage.content;
return true;
}
// Common alternatives
const candidates = [
['message'],
['prompt'],
['content'],
['text'],
['input']
];
for (const path of candidates) {
let obj = parsed;
for (let i = 0; i < path.length - 1; i++) {
if (!obj || typeof obj !== 'object') {
obj = null;
break;
}
obj = obj[path[i]];
}
if (!obj || typeof obj !== 'object') continue;
const key = path[path.length - 1];
if (typeof obj[key] === 'string' && !alreadyStamped(obj[key])) {
obj[key] = stampText + '\n\n' + obj[key];
return true;
}
}
// Search nested objects shallowly for "content" string fields
function scan(obj, depth = 0) {
if (!obj || typeof obj !== 'object' || depth > 4 || changed) return;
if (
typeof obj.content === 'string' &&
obj.content.trim() &&
!alreadyStamped(obj.content)
) {
obj.content = stampText + '\n\n' + obj.content;
changed = true;
return;
}
for (const key in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
const value = obj[key];
if (value && typeof value === 'object') {
scan(value, depth + 1);
if (changed) return;
}
}
}
scan(parsed);
return changed;
}
const originalFetch = window.fetch;
window.fetch = async function (...args) {
let [resource, config] = args;
const url = typeof resource === 'string' ? resource : resource.url;
const method = (config && config.method) ? config.method.toUpperCase() : 'GET';
if (
method === 'POST' &&
config &&
config.body &&
typeof config.body === 'string'
) {
try {
const parsed = JSON.parse(config.body);
const ts = buildTimestampParts();
const changed = tryStampPayload(parsed, ts.full);
if (changed) {
config = {
...config,
body: JSON.stringify(parsed)
};
showToast(`Timestamp: ${ts.plain}`);
}
} catch (e) {
// Silently skip if parsing fails
}
}
return originalFetch.apply(this, [resource, config]);
};
})();