helokopter / Disqus Spam Auto-Reload Persistent Linear

// ==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);

})();