Enhanced AutoScroll (Red/Black HUD, Allowlist Mode)

Smooth auto-scroll with HUD controls, hotkeys, and site allowlist (dark red theme, compact HUD). Press S to toggle, [ ] adjust speed, + - adjust step, R reset, H hide HUD. Allowlist via console command allowSite("domain"). Manage with listAllowSites(), removeSite("domain"), resetAllowlist(). Console logs info on each domain 👇

// ==UserScript==
// @name         Enhanced AutoScroll (Red/Black HUD, Allowlist Mode)
// @namespace    https://greasyfork.org/users/1513610
// @version      3.0
// @description  Smooth auto-scroll with HUD controls, hotkeys, and site allowlist (dark red theme, compact HUD). Press S to toggle, [ ] adjust speed, + - adjust step, R reset, H hide HUD. Allowlist via console command allowSite("domain"). Manage with listAllowSites(), removeSite("domain"), resetAllowlist(). Console logs info on each domain 👇
// @author       NAABO
// @match        *://*/*
// @grant        none
// ==/UserScript==

/*
📌 Features:
- Press 'S' to start/pause smooth scrolling.
- '[' / ']' decrease/increase scroll speed.
- '+' / '-' adjust speed step size.
- 'R' resets to default speed.
- 'H' shows/hides the HUD.
- Respects "prefers-reduced-motion".

📌 Allowlist Mode:
- Script runs ONLY on sites added to the allowlist.
- To allowlist a site, open DevTools console and run:
    allowSite("example.com");

📌 Console Helpers:
- allowSite("example.com") → add a site to allowlist
- removeSite("example.com") → remove a site from allowlist
- listAllowSites() → list all allowlisted sites
- resetAllowlist() → clear the allowlist
*/

(function () {
  'use strict';

  /************* Configuration *************/
  const CONFIG = {
    STORAGE_KEY: 'enhanced_autoscroll_config',
    ALLOWLIST_KEY: 'enhanced_autoscroll_allowlist',
    DEFAULT_SPEED: 250,
    DEFAULT_SPEED_STEP: 50,
    MIN_SPEED_STEP: 10,
    MAX_SPEED_STEP: 100,
    HUD_POSITIONS: ['bottom-right', 'bottom-left', 'top-right', 'top-left'],
    FLASH_DURATION: 1500,
  };

  /************* State *************/
  const state = {
    scrolling: false,
    speed: CONFIG.DEFAULT_SPEED,
    speedStep: CONFIG.DEFAULT_SPEED_STEP,
    hud: null,
    hudPositionIndex: 0,
    animationFrame: null,
    allowlist: JSON.parse(localStorage.getItem(CONFIG.ALLOWLIST_KEY) || '[]'),
  };

  /************* Utils *************/
  function saveConfig() {
    const data = {
      speed: state.speed,
      speedStep: state.speedStep,
      hudPositionIndex: state.hudPositionIndex,
    };
    localStorage.setItem(CONFIG.STORAGE_KEY, JSON.stringify(data));
  }

  function loadConfig() {
    const data = JSON.parse(localStorage.getItem(CONFIG.STORAGE_KEY) || '{}');
    if (data.speed) state.speed = data.speed;
    if (data.speedStep) state.speedStep = data.speedStep;
    if (data.hudPositionIndex != null) state.hudPositionIndex = data.hudPositionIndex;
  }

  function isAllowedSite() {
    return state.allowlist.includes(location.hostname);
  }

  function allowSite(domain) {
    if (!domain) domain = location.hostname;
    if (!state.allowlist.includes(domain)) {
      state.allowlist.push(domain);
      localStorage.setItem(CONFIG.ALLOWLIST_KEY, JSON.stringify(state.allowlist));
      console.log(`✅ ${domain} added to Enhanced AutoScroll allowlist. Reload the page to activate.`);
    } else {
      console.log(`⚠️ ${domain} is already in the allowlist.`);
    }
  }

  function removeSite(domain) {
    if (!domain) domain = location.hostname;
    if (state.allowlist.includes(domain)) {
      state.allowlist = state.allowlist.filter(d => d !== domain);
      localStorage.setItem(CONFIG.ALLOWLIST_KEY, JSON.stringify(state.allowlist));
      console.log(`🗑️ ${domain} removed from Enhanced AutoScroll allowlist.`);
    } else {
      console.log(`⚠️ ${domain} was not in the allowlist.`);
    }
  }

  function listAllowSites() {
    if (!state.allowlist.length) {
      console.log("📭 Allowlist is empty.");
    } else {
      console.log("📜 Enhanced AutoScroll allowlist:");
      state.allowlist.forEach((site, i) => {
        console.log(`${i + 1}. ${site}`);
      });
    }
  }

  function resetAllowlist() {
    state.allowlist = [];
    localStorage.setItem(CONFIG.ALLOWLIST_KEY, JSON.stringify([]));
    console.log("♻️ Enhanced AutoScroll allowlist reset to empty.");
  }

  // Expose helpers to console
  window.allowSite = allowSite;
  window.removeSite = removeSite;
  window.listAllowSites = listAllowSites;
  window.resetAllowlist = resetAllowlist;

  function flashHUD(msg) {
    if (!state.hud) return;
    const div = document.createElement('div');
    div.textContent = msg;
    div.style.cssText = `
      position:absolute; top:-24px; left:50%; transform:translateX(-50%);
      background:#b91c1c; color:#fff; padding:3px 6px;
      border-radius:4px; font-size:11px; pointer-events:none;
    `;
    state.hud.appendChild(div);
    setTimeout(() => div.remove(), CONFIG.FLASH_DURATION);
  }

  function getHUDPositionStyles() {
    switch (CONFIG.HUD_POSITIONS[state.hudPositionIndex]) {
      case 'bottom-left': return 'bottom:12px; left:12px;';
      case 'top-right': return 'top:12px; right:12px;';
      case 'top-left': return 'top:12px; left:12px;';
      default: return 'bottom:12px; right:12px;';
    }
  }

  /************* HUD *************/
  function createHUD() {
    if (state.hud) state.hud.remove();
    state.hud = document.createElement('div');
    state.hud.id = 'enhanced-autoscroll-hud';
    state.hud.style.cssText = `
      position:fixed; ${getHUDPositionStyles()} z-index:999999;
      padding:8px 10px; background:#111; color:#fff;
      font-family:monospace, system-ui, sans-serif;
      font-size:12px; border-radius:8px;
      box-shadow:0 4px 12px rgba(0,0,0,0.6);
      border:1px solid #b91c1c; opacity:0.95;
      max-width:300px;
    `;

    state.hud.innerHTML = `
      <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:6px;">
        <div id="hud-status" style="font-weight:bold; font-size:12px; color:#ef4444;">PAUSED</div>
        <button id="hud-close" style="
          background:none; border:none; color:#ef4444; font-size:14px;
          cursor:pointer; padding:0; line-height:1;
        " title="Close">&times;</button>
      </div>
      <div id="hud-speed" style="margin-bottom:6px; font-size:11px; color:#aaa;"></div>
      <div id="hud-buttons" style="display:flex; flex-wrap:wrap; gap:4px;">
        ${makeButton("S", "toggle", "Toggle scroll")}
        ${makeButton("[", "speed-down", "Decrease speed")}
        ${makeButton("]", "speed-up", "Increase speed")}
        ${makeButton("R", "reset", "Reset speed")}
        ${makeButton("H", "hide-hud", "Hide HUD")}
        ${makeButton("+", "step-up", "Increase step")}
        ${makeButton("-", "step-down", "Decrease step")}
      </div>
    `;
    document.body.appendChild(state.hud);

    state.hud.querySelector('#hud-close').addEventListener('click', shutdownScript);
    setupHUDButtons();
    updateHUD();
  }

  function makeButton(label, action, title) {
    return `
      <button class="hud-btn" data-action="${action}" title="${title}"
        style="
          background:#1a1a1a;
          border:1px solid #b91c1c;
          color:#f87171; font-size:12px;
          padding:2px 6px; border-radius:4px;
          cursor:pointer; transition:all 0.2s;
        "
        onmouseover="this.style.background='#b91c1c'; this.style.color='#fff';"
        onmouseout="this.style.background='#1a1a1a'; this.style.color='#f87171';"
      >${label}</button>
    `;
  }

  function setupHUDButtons() {
    state.hud.querySelectorAll('.hud-btn').forEach(btn => {
      btn.addEventListener('click', () => {
        handleAction(btn.dataset.action);
      });
    });
  }

  function updateHUD() {
    if (!state.hud) return;
    const status = state.hud.querySelector('#hud-status');
    status.textContent = state.scrolling ? 'SCROLLING' : 'PAUSED';
    status.style.color = state.scrolling ? '#22c55e' : '#ef4444';
    state.hud.querySelector('#hud-speed').textContent = `Speed: ${state.speed}px/s | Step: ${state.speedStep}`;
  }

  /************* Core *************/
  function handleAction(action) {
    switch (action) {
      case 'toggle': toggleScroll(); break;
      case 'speed-down': changeSpeed(-state.speedStep); break;
      case 'speed-up': changeSpeed(state.speedStep); break;
      case 'reset': resetSpeed(); break;
      case 'hide-hud': toggleHUD(); break;
      case 'step-up': changeStep(1); break;
      case 'step-down': changeStep(-1); break;
    }
    saveConfig();
    updateHUD();
  }

  function toggleScroll() {
    state.scrolling = !state.scrolling;
    if (state.scrolling) requestScroll();
    else cancelAnimationFrame(state.animationFrame);
    updateHUD();
  }

  function changeSpeed(delta) {
    state.speed = Math.max(0, state.speed + delta);
    flashHUD(`Speed: ${state.speed}px/s`);
  }

  function resetSpeed() {
    state.speed = CONFIG.DEFAULT_SPEED;
    flashHUD("🔄 Speed reset");
  }

  function changeStep(delta) {
    state.speedStep = Math.min(CONFIG.MAX_SPEED_STEP, Math.max(CONFIG.MIN_SPEED_STEP, state.speedStep + delta));
    flashHUD(`Step: ${state.speedStep}`);
  }

  function toggleHUD() {
    state.hud.style.display = state.hud.style.display === 'none' ? '' : 'none';
  }

  function requestScroll() {
    const step = state.speed / 60;
    window.scrollBy(0, step);
    state.animationFrame = requestAnimationFrame(requestScroll);
  }

  function shutdownScript() {
    cancelAnimationFrame(state.animationFrame);
    if (state.hud) state.hud.remove();
    document.removeEventListener('keydown', keyHandler);
  }

  /************* Keyboard *************/
  function keyHandler(e) {
    if (['INPUT', 'TEXTAREA'].includes(document.activeElement.tagName)) return;
    switch (e.key) {
      case 's': case 'S': handleAction('toggle'); break;
      case '[': handleAction('speed-down'); break;
      case ']': handleAction('speed-up'); break;
      case 'r': case 'R': handleAction('reset'); break;
      case 'h': case 'H': handleAction('hide-hud'); break;
      case '+': case '=': handleAction('step-up'); break;
      case '-': case '_': handleAction('step-down'); break;
    }
  }

  /************* Init *************/
  function init() {
    if (!isAllowedSite()) {
      console.log(`⚪ Enhanced AutoScroll inactive on ${location.hostname}`);
      console.log(`👉 To allowlist, run: allowSite("${location.hostname}")`);
      console.log(`👉 To list allowlisted sites, run: listAllowSites()`);
      return;
    }

    console.log(`✅ Enhanced AutoScroll active on ${location.hostname}`);
    console.log(`⚙️ Console helpers: allowSite("${location.hostname}"), removeSite("${location.hostname}"), listAllowSites(), resetAllowlist()`);

    loadConfig();
    createHUD();
    document.addEventListener('keydown', keyHandler);
    updateHUD();
  }

  init();

})();