Last active
December 3, 2025 22:11
-
-
Save SmugZombie/d8417afaa4456ea3aedb33b9ff794e9a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Datto RMM Idle Refresh Helper (Countdown + Ignore Paths) | |
| // @namespace http://tampermonkey.net/ | |
| // @version 1.4 | |
| // @description Refresh Datto RMM after idle periods to keep SSO sessions alive, with a countdown. Ignores certain paths. | |
| // @match https://zinfandel.rmm.datto.com/* | |
| // @grant GM_getValue | |
| // @grant GM_setValue | |
| // @grant GM_registerMenuCommand | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| // --- IGNORE PATHS HERE --- | |
| const IGNORED_PATH_PREFIXES = [ | |
| "/web-remote", // ignores /web-remote, /web-remote/..., /web-remoteXYZ... | |
| ]; | |
| function shouldIgnorePath() { | |
| const path = window.location.pathname; | |
| return IGNORED_PATH_PREFIXES.some(prefix => path.startsWith(prefix)); | |
| } | |
| // If the path should be ignored, do not initialize ANY idle/refresh behavior | |
| if (shouldIgnorePath()) { | |
| console.log("[Datto IdleRefresh] Ignored path:", window.location.pathname); | |
| return; | |
| } | |
| // --- CONFIG --- | |
| const INACTIVITY_MS = 3 * 1000; | |
| const REFRESH_DELAY_MS = 1 * 60 * 1000; | |
| // --- STATE --- | |
| let enabled = GM_getValue("datto_idle_refresh_enabled", true); | |
| let lastActivity = Date.now(); | |
| let idleTimer = null; | |
| let refreshTimer = null; | |
| let refreshCountdownInterval = null; | |
| let refreshTargetTime = null; | |
| let ui = null; | |
| function log(...a) { console.log("[Datto IdleRefresh]", ...a); } | |
| // ------------------------------------- | |
| // TIMER HELPERS | |
| // ------------------------------------- | |
| function clearIdleTimer() { | |
| if (idleTimer) { | |
| clearTimeout(idleTimer); | |
| idleTimer = null; | |
| } | |
| } | |
| function clearRefreshTimer() { | |
| if (refreshTimer) { | |
| clearTimeout(refreshTimer); | |
| refreshTimer = null; | |
| } | |
| refreshTargetTime = null; | |
| stopCountdown(); | |
| } | |
| function clearAllTimers() { | |
| clearIdleTimer(); | |
| clearRefreshTimer(); | |
| } | |
| function scheduleIdleTimer() { | |
| clearIdleTimer(); | |
| if (!enabled) return; | |
| idleTimer = setTimeout(handleIdle, INACTIVITY_MS); | |
| updateUI(); | |
| } | |
| function handleIdle() { | |
| if (!enabled) return; | |
| const now = Date.now(); | |
| const diff = now - lastActivity; | |
| if (diff < INACTIVITY_MS - 500) { | |
| scheduleIdleTimer(); | |
| return; | |
| } | |
| log("User idle detected. Scheduling refresh in", REFRESH_DELAY_MS / 1000, "seconds..."); | |
| scheduleRefresh(); | |
| } | |
| function scheduleRefresh() { | |
| clearRefreshTimer(); | |
| if (!enabled) return; | |
| refreshTargetTime = Date.now() + REFRESH_DELAY_MS; | |
| refreshTimer = setTimeout(doRefresh, REFRESH_DELAY_MS); | |
| startCountdown(); | |
| updateUI(); | |
| } | |
| function doRefresh() { | |
| if (!enabled) return; | |
| const now = Date.now(); | |
| const diff = now - lastActivity; | |
| if (diff < INACTIVITY_MS - 500) { | |
| log("Refresh canceled—user became active again."); | |
| clearRefreshTimer(); | |
| scheduleIdleTimer(); | |
| updateUI(); | |
| return; | |
| } | |
| log("Refreshing page due to inactivity..."); | |
| stopCountdown(); | |
| window.location.reload(); | |
| } | |
| // ------------------------------------- | |
| // USER ACTIVITY | |
| // ------------------------------------- | |
| const activityEvents = [ | |
| "mousemove", "mousedown", "mouseup", "click", | |
| "keydown", "keyup", "touchstart", "touchmove", | |
| "scroll", "focus" | |
| ]; | |
| function onActivity() { | |
| if (!enabled) return; | |
| lastActivity = Date.now(); | |
| clearRefreshTimer(); | |
| scheduleIdleTimer(); | |
| updateUI(); | |
| } | |
| // ------------------------------------- | |
| // COUNTDOWN UI | |
| // ------------------------------------- | |
| function startCountdown() { | |
| stopCountdown(); | |
| if (!refreshTargetTime) return; | |
| refreshCountdownInterval = setInterval(updateUI, 1000); | |
| } | |
| function stopCountdown() { | |
| if (refreshCountdownInterval) { | |
| clearInterval(refreshCountdownInterval); | |
| refreshCountdownInterval = null; | |
| } | |
| } | |
| // ------------------------------------- | |
| // TOGGLE UI | |
| // ------------------------------------- | |
| function createUI() { | |
| if (ui) return; | |
| ui = document.createElement("div"); | |
| ui.id = "datto-idle-refresh-toggle"; | |
| Object.assign(ui.style, { | |
| position: "fixed", | |
| bottom: "60px", | |
| right: "10px", | |
| zIndex: 999999, | |
| padding: "6px 10px", | |
| background: "#222", | |
| color: "#fff", | |
| fontSize: "12px", | |
| fontFamily: "Arial, sans-serif", | |
| borderRadius: "4px", | |
| cursor: "pointer", | |
| opacity: "0.75", | |
| transition: "opacity 0.2s, background 0.2s", | |
| userSelect: "none" | |
| }); | |
| ui.addEventListener("mouseenter", () => { | |
| ui.style.opacity = "1"; | |
| ui.style.background = enabled ? "#28a745" : "#666"; | |
| }); | |
| ui.addEventListener("mouseleave", () => { | |
| ui.style.opacity = "0.75"; | |
| ui.style.background = "#222"; | |
| }); | |
| ui.addEventListener("click", () => { | |
| enabled = !enabled; | |
| GM_setValue("datto_idle_refresh_enabled", enabled); | |
| clearAllTimers(); | |
| stopCountdown(); | |
| if (enabled) { | |
| lastActivity = Date.now(); | |
| scheduleIdleTimer(); | |
| } | |
| updateUI(); | |
| }); | |
| document.body.appendChild(ui); | |
| updateUI(); | |
| } | |
| function updateUI() { | |
| if (!ui) return; | |
| if (!enabled) { | |
| ui.textContent = "Datto Idle Refresh: OFF (paused)"; | |
| return; | |
| } | |
| if (refreshTimer && refreshTargetTime) { | |
| const msLeft = refreshTargetTime - Date.now(); | |
| const secondsLeft = Math.max(0, Math.ceil(msLeft / 1000)); | |
| ui.textContent = `Datto Idle Refresh: ON (refresh in ${secondsLeft}s)`; | |
| return; | |
| } | |
| ui.textContent = "Datto Idle Refresh: ON (monitoring activity)"; | |
| } | |
| // ------------------------------------- | |
| // MENU COMMAND | |
| // ------------------------------------- | |
| GM_registerMenuCommand("Toggle idle refresh", () => { | |
| enabled = !enabled; | |
| GM_setValue("datto_idle_refresh_enabled", enabled); | |
| clearAllTimers(); | |
| stopCountdown(); | |
| if (enabled) { | |
| lastActivity = Date.now(); | |
| scheduleIdleTimer(); | |
| } | |
| updateUI(); | |
| }); | |
| // ------------------------------------- | |
| // INIT | |
| // ------------------------------------- | |
| function init() { | |
| if (shouldIgnorePath()) { | |
| console.log("[Datto IdleRefresh] Ignored path:", window.location.pathname); | |
| return; | |
| } | |
| createUI(); | |
| activityEvents.forEach(evt => | |
| window.addEventListener(evt, onActivity, { passive: true }) | |
| ); | |
| document.addEventListener("visibilitychange", () => { | |
| if (!document.hidden) onActivity(); | |
| }); | |
| if (enabled) { | |
| scheduleIdleTimer(); | |
| } | |
| updateUI(); | |
| log("Initialized."); | |
| } | |
| if (document.readyState === "loading") { | |
| document.addEventListener("DOMContentLoaded", init); | |
| } else { | |
| init(); | |
| } | |
| })(); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment