| 75 | return null; |
| 76 | } |
| 77 | function formatTimeLeft(ms) { |
| 78 | if (ms <= 0) |
| 79 | return 'now'; |
| 80 | const totalSec = Math.floor(ms / 1000); |
| 81 | const h = Math.floor(totalSec / 3600); |
| 82 | const m = Math.floor((totalSec % 3600) / 60); |
| 83 | const s = totalSec % 60; |
| 84 | const parts = []; |
| 85 | if (h) |
| 86 | parts.push(`${h}h`); |
| 87 | if (m) |
| 88 | parts.push(`${m}m`); |
| 89 | if (s || parts.length === 0) |
| 90 | parts.push(`${s}s`); |
| 91 | return parts.join(' '); |
| 92 | } |
| 93 | // ── Scheduler Engine ─────────────────────────────────────────────────────── |
| 94 | // Started once when bot connects — checks every 10s for due messages |
| 95 | let _engineStarted = false; |