Universal Auto-Scroll

Adds auto-scrolling functionality to any website

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         Universal Auto-Scroll
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Adds auto-scrolling functionality to any website
// @author       You
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    // Wait a bit for page to be fully ready
    setTimeout(initAutoScroll, 1000);

    function initAutoScroll() {
        // Configuration
        const DEFAULT_SETTINGS = {
            isActive: false,
            speed: 3,
            isMinimized: false,
            pixelsPerSecond: 50  // Base scrolling speed - will be modified by speed setting
        };

        // State variables
        let isScrolling = false;
        let scrollIntervalId = null;
        let userScrollDetected = false;
        let userScrollTimeout = null;
        let lastScrollPosition = window.scrollY;

        // Load saved settings or use defaults - Using Tampermonkey's built-in storage
        let scrollSettings;
        try {
            scrollSettings = JSON.parse(GM_getValue('autoScrollSettings', JSON.stringify(DEFAULT_SETTINGS)));
        } catch (e) {
            console.log('Could not load settings, using defaults');
            scrollSettings = DEFAULT_SETTINGS;
        }

        // DOM elements references
        let autoScrollPanel;
        let bubbleView;
        let toggleButton;
        let speedSlider;
        let speedValue;

        // Create and inject the UI
        function createUI() {
            // Create a container for our elements with a unique ID
            const containerId = 'auto-scroll-container-' + Math.random().toString(36).substr(2, 9);
            const container = document.createElement('div');
            container.id = containerId;
            document.body.appendChild(container);

            // Add isolated styles to avoid conflicts with page CSS
            const styleElement = document.createElement('style');
            styleElement.textContent = `
                #${containerId} {
                    all: initial;
                    font-family: Arial, sans-serif;
                    color: white;
                    font-size: 14px;
                }
                #${containerId} * {
                    all: unset;
                    box-sizing: border-box;
                }
                #${containerId} .auto-scroll-panel {
                    position: fixed;
                    bottom: 80px;
                    right: 20px;
                    background-color: rgba(0, 0, 0, 0.8);
                    color: white;
                    padding: 15px;
                    border-radius: 8px;
                    width: 220px;
                    z-index: 9999999;
                    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
                    font-family: Arial, sans-serif;
                    display: ${scrollSettings.isMinimized ? 'none' : 'block'};
                }
                #${containerId} .panel-header {
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    margin-bottom: 10px;
                    border-bottom: 1px solid rgba(255, 255, 255, 0.2);
                    padding-bottom: 8px;
                }
                #${containerId} .panel-title {
                    font-weight: bold;
                    font-size: 16px;
                    display: block;
                }
                #${containerId} .minimize-button {
                    background: none;
                    border: none;
                    color: white;
                    cursor: pointer;
                    font-size: 20px;
                    padding: 0;
                    margin: 0;
                    display: block;
                }
                #${containerId} .section {
                    margin-bottom: 12px;
                }
                #${containerId} .section-title {
                    font-size: 14px;
                    color: #ffcc00;
                    margin-bottom: 8px;
                    display: block;
                }
                #${containerId} .toggle-button {
                    background-color: #2196F3;
                    border: none;
                    color: white;
                    padding: 10px 15px;
                    text-align: center;
                    text-decoration: none;
                    font-size: 14px;
                    border-radius: 6px;
                    width: 100%;
                    cursor: pointer;
                    display: flex;
                    justify-content: center;
                    align-items: center;
                    gap: 8px;
                    margin-bottom: 10px;
                }
                #${containerId} .toggle-button.active {
                    background-color: #4CAF50;
                }
                #${containerId} .slider-container {
                    width: 100%;
                    display: flex;
                    flex-direction: column;
                    gap: 8px;
                }
                #${containerId} .slider-top {
                    display: flex;
                    justify-content: space-between;
                    width: 100%;
                }
                #${containerId} .speed-value {
                    font-weight: bold;
                }
                #${containerId} .speed-slider {
                    width: 100%;
                    height: 5px;
                    -webkit-appearance: none;
                    appearance: none;
                    background: #444;
                    outline: none;
                    border-radius: 3px;
                    display: block;
                }
                #${containerId} .speed-slider::-webkit-slider-thumb {
                    -webkit-appearance: none;
                    appearance: none;
                    width: 15px;
                    height: 15px;
                    border-radius: 50%;
                    background: #ffcc00;
                    cursor: pointer;
                }
                #${containerId} .speed-slider::-moz-range-thumb {
                    width: 15px;
                    height: 15px;
                    border-radius: 50%;
                    background: #ffcc00;
                    cursor: pointer;
                }
                #${containerId} .slider-labels {
                    display: flex;
                    justify-content: space-between;
                    width: 100%;
                }
                #${containerId} .auto-scroll-bubble {
                    position: fixed;
                    bottom: 80px;
                    right: 20px;
                    width: 60px;
                    height: 60px;
                    border-radius: 50%;
                    background-color: rgba(0, 0, 0, 0.8);
                    display: ${scrollSettings.isMinimized ? 'flex' : 'none'};
                    flex-direction: column;
                    justify-content: center;
                    align-items: center;
                    cursor: pointer;
                    z-index: 9999999;
                    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
                    font-size: 24px;
                }
            `;
            document.head.appendChild(styleElement);

            // Create the main panel
            autoScrollPanel = document.createElement('div');
            autoScrollPanel.className = 'auto-scroll-panel';
            container.appendChild(autoScrollPanel);

            // Create panel header with title and minimize button
            const panelHeader = document.createElement('div');
            panelHeader.className = 'panel-header';

            const panelTitle = document.createElement('div');
            panelTitle.className = 'panel-title';
            panelTitle.textContent = 'Auto-Scroll Controls';

            const minimizeButton = document.createElement('button');
            minimizeButton.className = 'minimize-button';
            minimizeButton.textContent = '−';
            minimizeButton.addEventListener('click', toggleMinimize);

            panelHeader.appendChild(panelTitle);
            panelHeader.appendChild(minimizeButton);
            autoScrollPanel.appendChild(panelHeader);

            // Create scrolling status section
            const statusSection = document.createElement('div');
            statusSection.className = 'section';

            const statusTitle = document.createElement('div');
            statusTitle.className = 'section-title';
            statusTitle.textContent = 'Scrolling Status';

            toggleButton = document.createElement('button');
            toggleButton.className = 'toggle-button' + (scrollSettings.isActive ? ' active' : '');
            toggleButton.innerHTML = scrollSettings.isActive ?
                '<span>⏸️</span> Pause Scrolling' :
                '<span>▶️</span> Start Scrolling';
            toggleButton.addEventListener('click', toggleScrolling);

            statusSection.appendChild(statusTitle);
            statusSection.appendChild(toggleButton);
            autoScrollPanel.appendChild(statusSection);

            // Create speed control section
            const speedSection = document.createElement('div');
            speedSection.className = 'section';

            const speedTitle = document.createElement('div');
            speedTitle.className = 'section-title';
            speedTitle.textContent = 'Scroll Speed';

            const sliderContainer = document.createElement('div');
            sliderContainer.className = 'slider-container';

            const sliderTop = document.createElement('div');
            sliderTop.className = 'slider-top';

            const speedLabel = document.createElement('span');
            speedLabel.textContent = 'Speed:';

            speedValue = document.createElement('span');
            speedValue.className = 'speed-value';
            updateSpeedDisplay(scrollSettings.speed);

            sliderTop.appendChild(speedLabel);
            sliderTop.appendChild(speedValue);

            speedSlider = document.createElement('input');
            speedSlider.type = 'range';
            speedSlider.className = 'speed-slider';
            speedSlider.min = '1';
            speedSlider.max = '5';
            speedSlider.value = scrollSettings.speed;
            speedSlider.addEventListener('input', handleSpeedChange);

            const sliderLabels = document.createElement('div');
            sliderLabels.className = 'slider-labels';

            const slowLabel = document.createElement('span');
            slowLabel.textContent = 'Slow';

            const fastLabel = document.createElement('span');
            fastLabel.textContent = 'Fast';

            sliderLabels.appendChild(slowLabel);
            sliderLabels.appendChild(fastLabel);

            sliderContainer.appendChild(sliderTop);
            sliderContainer.appendChild(speedSlider);
            sliderContainer.appendChild(sliderLabels);

            speedSection.appendChild(speedTitle);
            speedSection.appendChild(sliderContainer);
            autoScrollPanel.appendChild(speedSection);

            // Create bubble view (minimized version)
            bubbleView = document.createElement('div');
            bubbleView.className = 'auto-scroll-bubble';
            bubbleView.innerHTML = '📜';
            bubbleView.addEventListener('click', toggleMinimize);
            container.appendChild(bubbleView);

            // Start scrolling if it was active before
            if (scrollSettings.isActive) {
                startScrolling();
            }
        }

        // Toggle between expanded panel and minimized bubble
        function toggleMinimize() {
            scrollSettings.isMinimized = !scrollSettings.isMinimized;

            if (scrollSettings.isMinimized) {
                autoScrollPanel.style.display = 'none';
                bubbleView.style.display = 'flex';
            } else {
                autoScrollPanel.style.display = 'block';
                bubbleView.style.display = 'none';
            }

            saveSettings();
        }

        // Toggle scrolling on/off
        function toggleScrolling() {
            scrollSettings.isActive = !scrollSettings.isActive;

            if (scrollSettings.isActive) {
                // Start scrolling
                toggleButton.classList.add('active');
                toggleButton.innerHTML = '<span>⏸️</span> Pause Scrolling';
                startScrolling();
            } else {
                // Pause scrolling
                toggleButton.classList.remove('active');
                toggleButton.innerHTML = '<span>▶️</span> Start Scrolling';
                stopScrolling();
            }

            saveSettings();
        }

        // Handle speed slider changes
        function handleSpeedChange() {
            const value = parseInt(speedSlider.value);
            scrollSettings.speed = value;
            updateSpeedDisplay(value);

            // If currently scrolling, update the scroll speed
            if (isScrolling) {
                stopScrolling();
                startScrolling();
            }

            saveSettings();
        }

        // Update speed display text
        function updateSpeedDisplay(value) {
            let speedText;

            if (value === 1) speedText = "Very Slow";
            else if (value === 2) speedText = "Slow";
            else if (value === 3) speedText = "Medium";
            else if (value === 4) speedText = "Fast";
            else speedText = "Very Fast";

            speedValue.textContent = `${speedText} (${value})`;
        }

        // Start auto-scrolling
        function startScrolling() {
            if (isScrolling) return;

            isScrolling = true;
            lastScrollPosition = window.scrollY;

            // Calculate scroll speed based on setting (1-5)
            // The base speed (pixelsPerSecond) is multiplied by a factor based on the speed setting
            const speedFactors = [0.5, 0.75, 1, 1.5, 2.5]; // Factors for speeds 1-5
            const pixelsPerSecond = DEFAULT_SETTINGS.pixelsPerSecond * speedFactors[scrollSettings.speed - 1];

            // Convert pixels per second to interval delay in milliseconds
            // We'll scroll 1px at a time for smoothness
            const scrollDelay = Math.floor(1000 / pixelsPerSecond);

            // Start scroll interval
            scrollIntervalId = setInterval(function() {
                // Only scroll if user isn't manually scrolling
                if (!userScrollDetected) {
                    window.scrollBy(0, 1);
                }
            }, scrollDelay);
        }

        // Stop auto-scrolling
        function stopScrolling() {
            if (!isScrolling) return;

            isScrolling = false;
            if (scrollIntervalId !== null) {
                clearInterval(scrollIntervalId);
                scrollIntervalId = null;
            }
        }

        // Save settings using Tampermonkey's storage
        function saveSettings() {
            try {
                GM_setValue('autoScrollSettings', JSON.stringify(scrollSettings));
            } catch (e) {
                console.error('Failed to save settings:', e);
            }
        }

        // Handle user manual scrolling
        function handleUserScroll() {
            const currentPosition = window.scrollY;

            // If position changed significantly (more than what our auto-scroll would do)
            // and we're currently auto-scrolling, pause temporarily
            if (isScrolling && Math.abs(currentPosition - lastScrollPosition) > 3) {
                userScrollDetected = true;

                // Clear existing timeout if there is one
                if (userScrollTimeout) {
                    clearTimeout(userScrollTimeout);
                }

                // Set timeout to resume auto-scrolling after user stops scrolling
                userScrollTimeout = setTimeout(function() {
                    userScrollDetected = false;
                    lastScrollPosition = window.scrollY;
                }, 5000); // 5-second delay before resuming
            }

            lastScrollPosition = currentPosition;
        }

        // Only create UI if we're on a page with scrollable content
        if (document.body && document.body.scrollHeight > window.innerHeight) {
            createUI();

            // Add scroll event listener to detect manual user scrolling
            window.addEventListener('scroll', handleUserScroll, { passive: true });

            // Clean up when page is unloaded
            window.addEventListener('beforeunload', function() {
                if (scrollIntervalId !== null) {
                    clearInterval(scrollIntervalId);
                }
            });
        }
    }
})();