Finviz Refresh Overhaul

Adds custom refresh buttons and enables a high-speed refresh mode.

// ==UserScript==
// @name        Finviz Refresh Overhaul
// @namespace   http://tampermonkey.net/
// @version     1.0
// @description Adds custom refresh buttons and enables a high-speed refresh mode.
// @author      Game Abuse Studios
// @match       https://elite.finviz.com/screener.ashx*
// @license MIT
// @grant       none
// @run-at      document-idle
// ==/UserScript==

(function() {
    'use strict';

    /**
     * Checks for a stored refresh interval and reapplies it to the URL if needed.
     * This runs once at the very start of the script.
     */
    function applyStoredInterval() {
        const currentUrl = new URL(window.location.href);
        const activeRefresh = currentUrl.searchParams.get('ar');
        const storedRefresh = localStorage.getItem('finvizRefreshInterval');

        // If there's no refresh interval in the URL but one is stored,
        // we redirect to the URL with the stored value.
        if (!activeRefresh && storedRefresh) {
            currentUrl.searchParams.set('ar', storedRefresh);
            window.location.replace(currentUrl.href);
        }
    }

    // --- Secondary Script Logic for Fast Refresh ---

    /**
     * Activates the high-speed refresh timer.
     * It overrides the default Finviz refresh function.
     * @param {number} interval - The refresh interval in milliseconds.
     */
    function activateFastRefresh(interval) {
        // Prevent the original refresh timer from ever being set.
        if (typeof window.ScreenerRefreshInit === 'function') {
            window.ScreenerRefreshInit = function() { /* Do nothing */ };
        }

        // Clear any existing custom timer before setting a new one.
        if (window.myCustomRefreshTimerId) {
            clearInterval(window.myCustomRefreshTimerId);
        }

        // Set our new refresh timer to run at the specified interval.
        if (typeof window.Refresh === 'function') {
            window.myCustomRefreshTimerId = setInterval(() => {
                window.Refresh();
            }, interval);
        }
    }

    /**
     * Deactivates the high-speed refresh timer and allows
     * Finviz's default behavior to resume.
     */
    function deactivateFastRefresh() {
        if (window.myCustomRefreshTimerId) {
            clearInterval(window.myCustomRefreshTimerId);
            window.myCustomRefreshTimerId = null;
        }
    }

    /**
     * Wipes the existing refresh links and rebuilds the entire set with custom options included.
     * @param {HTMLElement} container - The element where buttons should be rebuilt.
     */
    function rebuildButtons(container) {
        // Define ALL buttons in the desired final order.
        const allButtons = [
            { text: '0.25s', value: '0.25' },
            { text: '1s', value: '1' },
            { text: '5s', value: '5' },
            { text: '10s', value: '10' },
            { text: '1min', value: '60' },
            { text: 'off', value: null }
        ];

        // Find the specific span inside the container that holds the links.
        const buttonHolder = container.querySelector('span[style*="white-space: nowrap"]');
        if (!buttonHolder) return;

        // --- Wipe existing buttons ---
        buttonHolder.innerHTML = ''; // Clear everything inside the span.

        // Get the current URL to determine which link should be active.
        const currentUrl = new URL(window.location.href);
        const activeRefresh = currentUrl.searchParams.get('ar');

        // --- Rebuild from scratch ---
        const refreshTextSpan = document.createElement('span');
        refreshTextSpan.textContent = 'Refresh: ';
        refreshTextSpan.style.color = '#676F85';
        refreshTextSpan.style.fontWeight = 'bold';
        buttonHolder.appendChild(refreshTextSpan);

        allButtons.forEach((button, index) => {
            const link = document.createElement('a');
            link.className = 'tab-link';
            link.textContent = button.text;

            // Add event listener to save the selection to local storage
            link.addEventListener('click', () => {
                if (button.value) {
                    localStorage.setItem('finvizRefreshInterval', button.value);
                } else {
                    localStorage.removeItem('finvizRefreshInterval');
                }
            });

            const url = new URL(window.location.href);
            if (button.value) {
                url.searchParams.set('ar', button.value);
            } else {
                url.searchParams.delete('ar');
            }
            link.href = url.href;

            const isActive = (button.value === activeRefresh) || (!button.value && !activeRefresh);
            if (isActive) {
                link.classList.add('font-bold');
            }

            buttonHolder.appendChild(link);

            if (index < allButtons.length - 1) {
                buttonHolder.appendChild(document.createTextNode(' | '));
            }
        });

        // --- Handle the secondary script activation ---
        if (activeRefresh === '0.25') {
            activateFastRefresh(250); // 250ms for 0.25s
        } else if (activeRefresh === '1') {
            activateFastRefresh(1000); // 1000ms for 1s
        } else if (activeRefresh === '5') {
            activateFastRefresh(5000); // 5000ms for 5s
        } else {
            deactivateFastRefresh();
        }
    }

    /**
     * The main observer that watches for Finviz wiping our buttons.
     */
    const mainObserver = new MutationObserver(() => {
        const container = document.getElementById('screener-fullview-links');
        // If our buttons are gone, rebuild them.
        if (container && !container.querySelector('a[href*="&ar=0.25"]')) {
            rebuildButtons(container);
        }
    });

    /**
     * This function checks if the page is ready for our script to run.
     * It looks for the container and at least one link inside it.
     */
    function initialize() {
        const container = document.getElementById('screener-fullview-links');
        const anyLinkInside = container ? container.querySelector('a.tab-link') : null;

        if (container && anyLinkInside) {
            // We're ready! Stop the checking.
            clearInterval(setupInterval);

            // Rebuild the buttons for the first time.
            rebuildButtons(container);

            // Start the permanent observer to watch for subsequent changes by Finviz.
            mainObserver.observe(container, { childList: true, subtree: true });
        }
    }

    // --- Main Execution Block ---

    // 1. First, check if we need to redirect based on a stored value.
    applyStoredInterval();

    // 2. Then, begin the process of initializing the buttons on the page.
    const setupInterval = setInterval(initialize, 1);
})();