From b884f23b13abecc57feea1792ca8f4fb767698e6 Mon Sep 17 00:00:00 2001 From: legop3 Date: Wed, 7 Jan 2026 23:06:55 -0500 Subject: [PATCH] ts command :3 --- server/config.example.yaml | 1 + server/src/services/discordBotService.js | 77 +++++++++++++++++++++++- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/server/config.example.yaml b/server/config.example.yaml index 2b8fc520..1d2f0106 100644 --- a/server/config.example.yaml +++ b/server/config.example.yaml @@ -7,6 +7,7 @@ admins: password_hash: "$2b$10$n0L0oe1ZQy7IgM.FvVAzb.aXz43uaZWFiT0wr.05uNoVIDLawmrCG" # password: lockdownpass discord_id: "0987654321" lockdown: true +timezone: "America/New_York" media: # Base address for mediaMTX (scheme + host + optional port/path). The UI will always request # http:////whep diff --git a/server/src/services/discordBotService.js b/server/src/services/discordBotService.js index 03de1c3b..c384e01d 100644 --- a/server/src/services/discordBotService.js +++ b/server/src/services/discordBotService.js @@ -192,6 +192,7 @@ function formatHelp() { '`rs lock ` — lock a rover', '`rs unlock ` — unlock a rover', '`rs mode ` — change server mode', + '`ts` — show time status', ].join('\n'); } @@ -394,7 +395,12 @@ async function handleModeCommand(message, mode) { async function handleCommand(message) { if (message.author.bot) return; const content = (message.content || '').trim(); - if (!content.toLowerCase().startsWith('rs')) return; + const lower = content.toLowerCase(); + if (lower === 'ts' || lower.startsWith('ts ')) { + await handleTimeStatusCommand(message); + return; + } + if (!lower.startsWith('rs')) return; const tokens = content.split(/\s+/); tokens.shift(); // remove prefix @@ -447,7 +453,8 @@ async function handleBridgeInbound(message) { if (String(message.channelId) !== String(bridgeChannelId)) return; if (message.author.bot) return; const content = (message.content || '').trim(); - if (content.toLowerCase().startsWith('rs')) return; // don't echo commands + const lower = content.toLowerCase(); + if (lower.startsWith('rs') || lower === 'ts' || lower.startsWith('ts ')) return; // don't echo commands const nickname = message.member?.nickname || message.author?.globalName || message.author?.username || 'Discord'; const role = isAdminUser(message.author.id) ? 'admin' : 'user'; @@ -470,6 +477,72 @@ function buildEmbed({ title, description, color }) { return embed; } +function getServerTimezone() { + return config.timezone || config.server?.timezone || process.env.TZ || 'America/New_York'; +} + +function formatTimeInZone(date, timeZone) { + try { + const formatter = new Intl.DateTimeFormat('en-US', { + timeZone, + hour: '2-digit', + minute: '2-digit', + hour12: false, + }); + return formatter.format(date); + } catch (err) { + return 'n/a'; + } +} + +function buildTimeStatusEmbed() { + const serverTimezone = getServerTimezone(); + const now = new Date(); + const zones = [ + { label: 'UTC', zone: 'UTC' }, + { label: 'US Pacific', zone: 'America/Los_Angeles' }, + { label: 'US Mountain', zone: 'America/Denver' }, + { label: 'US Central', zone: 'America/Chicago' }, + { label: 'US Eastern', zone: 'America/New_York' }, + { label: 'Europe London', zone: 'Europe/London' }, + { label: 'Europe Berlin', zone: 'Europe/Berlin' }, + { label: 'Asia Kolkata', zone: 'Asia/Kolkata' }, + { label: 'Asia Shanghai', zone: 'Asia/Shanghai' }, + { label: 'Asia Tokyo', zone: 'Asia/Tokyo' }, + { label: 'Australia Sydney', zone: 'Australia/Sydney' }, + ]; + + const entries = zones.map((entry) => { + const time = formatTimeInZone(now, entry.zone); + const highlight = + String(entry.zone).toLowerCase() === String(serverTimezone).toLowerCase() + ? ' **(server local timezone)**' + : ''; + return `${entry.label} — ${time}${highlight}`; + }); + + if (!zones.some((entry) => String(entry.zone).toLowerCase() === String(serverTimezone).toLowerCase())) { + const time = formatTimeInZone(now, serverTimezone); + entries.push(`Server Local — ${time} **(server local timezone)**`); + } + + const embed = buildEmbed({ + title: 'Time Status', + description: entries.join('\n'), + color: 0x2196f3, + }); + embed.setFooter({ text: `Server local timezone: ${serverTimezone}` }); + return embed; +} + +async function handleTimeStatusCommand(message) { + const embed = buildTimeStatusEmbed(); + await message.reply({ + embeds: [embed], + allowedMentions: { parse: [], repliedUser: false }, + }); +} + function buildBatteryStatusEmbed(color, records = null) { const embed = buildEmbed({ title: 'Rover Battery Status', color: color || 0x2196f3 }); const baseRecords = records || Array.from(rovers.values());