NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Disqus Spam Auto-Reload Persistent Linear
// @namespace http://tampermonkey.net/
// @version 8.6
// @license MIT
// @description Reload → wait 2s → detect spam → beep → countdown → reload (linear, persistent)
// @match https://*.disqus.com/admin/moderate/*
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
(function() {
'use strict';
// -------------------------------------
// CONFIG / PERSISTED STATE
// -------------------------------------
let running = GM_getValue("running", false);
let interval = GM_getValue("interval", 20);
let countdown = interval;
let countdownTimer = null;
// LOAD SAVED PANEL POSITION
const savedLeft = GM_getValue("panelLeft", 20);
const savedTop = GM_getValue("panelTop", 80);
// -------------------------------------
// PANEL UI
// -------------------------------------
const panel = document.createElement("div");
panel.style.cssText = `
position: fixed;
top: ${savedTop}px;
left: ${savedLeft}px;
background: #222;
color: white;
padding: 12px;
z-index: 9999999;
width: 220px;
border-radius: 10px;
font-family: sans-serif;
user-select: none;
cursor: move;
`;
panel.innerHTML = `
<div style="font-size:15px;font-weight:bold;margin-bottom:5px;">Disqus Auto-Reload</div>
<button id="toggleBtn" style="width:100%;padding:8px;font-size:14px;font-weight:bold;border:none;border-radius:6px;cursor:pointer;">
</button>
<button id="testSound" style="margin-top:8px;width:100%;padding:6px;font-size:13px;border:none;border-radius:6px;cursor:pointer;background:#007bff;color:white;">
Test Sound
</button>
<div style="margin-top:10px;">Reload every:
<span id="ivalLabel">${interval}</span>s
</div>
<input id="ivalSlider" type="range" min="5" max="120" value="${interval}" style="width:100%;margin-top:3px;">
<div style="margin-top:8px;">Next reload in: <span id="countdownLabel">${interval}</span>s</div>
`;
document.body.appendChild(panel);
const toggleBtn = panel.querySelector("#toggleBtn");
const testBtn = panel.querySelector("#testSound");
const ivalSlider = panel.querySelector("#ivalSlider");
const ivalLabel = panel.querySelector("#ivalLabel");
const countdownLabel = panel.querySelector("#countdownLabel");
// -------------------------------------
// BUTTONS / SLIDER
// -------------------------------------
function updateButton() {
if (running) {
toggleBtn.textContent = "RUNNING";
toggleBtn.style.background = "#28a745";
toggleBtn.style.color = "black";
} else {
toggleBtn.textContent = "STOPPED";
toggleBtn.style.background = "#dc3545";
toggleBtn.style.color = "white";
}
}
updateButton();
toggleBtn.onclick = () => {
running = !running;
GM_setValue("running", running);
updateButton();
if (running) startLinearCycle();
};
ivalSlider.oninput = () => {
interval = Number(ivalSlider.value);
GM_setValue("interval", interval);
ivalLabel.textContent = interval;
countdown = interval;
countdownLabel.textContent = countdown;
};
// -------------------------------------
// AUDIO BEEP
// -------------------------------------
const beepAudio = document.createElement("audio");
beepAudio.src = "https://actions.google.com/sounds/v1/alarms/beep_short.ogg";
beepAudio.volume = 0.3;
beepAudio.preload = "auto";
document.body.appendChild(beepAudio);
function beepTriplet() {
for (let i = 0; i < 3; i++) {
setTimeout(() => {
beepAudio.currentTime = 0;
beepAudio.play();
}, i * 300);
}
}
testBtn.onclick = () => beepTriplet();
// -------------------------------------
// LINEAR CYCLE (exact behavior preserved)
// -------------------------------------
function startLinearCycle() {
if (!running) return;
location.reload();
}
window.addEventListener("load", () => {
if (!running) return;
setTimeout(() => {
const spamPosts = document.querySelectorAll("time.time-ago");
if (spamPosts.length > 0) beepTriplet();
countdown = interval;
countdownLabel.textContent = countdown;
startCountdownTimer();
}, 2000);
});
function startCountdownTimer() {
if (countdownTimer) clearInterval(countdownTimer);
countdownTimer = setInterval(() => {
if (!running) return;
countdown--;
if (countdown <= 0) {
clearInterval(countdownTimer);
countdownTimer = null;
startLinearCycle();
}
countdownLabel.textContent = countdown;
}, 1000);
}
// -------------------------------------
// TOUCH + MOUSE DRAGGING (with persistence)
// -------------------------------------
let isDragging = false;
let startX = 0, startY = 0;
let initialLeft = 0, initialTop = 0;
function getClientPos(e) {
if (e.touches && e.touches.length > 0) {
return { x: e.touches[0].clientX, y: e.touches[0].clientY };
}
return { x: e.clientX, y: e.clientY };
}
function dragStart(e) {
if (e.target.tagName === "INPUT" || e.target.tagName === "BUTTON") return;
const pos = getClientPos(e);
isDragging = true;
startX = pos.x;
startY = pos.y;
initialLeft = panel.offsetLeft;
initialTop = panel.offsetTop;
e.preventDefault();
}
function dragMove(e) {
if (!isDragging) return;
const pos = getClientPos(e);
const dx = pos.x - startX;
const dy = pos.y - startY;
panel.style.left = (initialLeft + dx) + "px";
panel.style.top = (initialTop + dy) + "px";
e.preventDefault();
}
function dragEnd() {
if (!isDragging) return;
isDragging = false;
GM_setValue("panelLeft", panel.offsetLeft);
GM_setValue("panelTop", panel.offsetTop);
}
// Mouse
panel.addEventListener("mousedown", dragStart);
document.addEventListener("mousemove", dragMove);
document.addEventListener("mouseup", dragEnd);
// Touch
panel.addEventListener("touchstart", dragStart, { passive: false });
document.addEventListener("touchmove", dragMove, { passive: false });
document.addEventListener("touchend", dragEnd);
document.addEventListener("touchcancel", dragEnd);
})();