Page Progess counter for Weebcentral

Shows "current page/total pages" on the bottom-left of the window for reading websites.

// ==UserScript==
// @name         Page Progess counter for Weebcentral
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  Shows "current page/total pages" on the bottom-left of the window for reading websites.
// @author       Nirmal Bhasarkar
// @license      MIT
// @match        https://weebcentral.com/chapters/*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    const config = {
        // --- POSITIONING ---
        counterPosition: {
            bottom: '5px', // Modify this two values to move the box location
            left: '5px'
        },
    };
    // --- End of Configuration ---

    let pageCounterElement;
    let cachedTotalPages = null;
    let observer;

    function debounce(func, delay) {
        let debounceTimer;
        return function(...args) {
            clearTimeout(debounceTimer);
            debounceTimer = setTimeout(() => func.apply(this, args), delay);
        };
    }

    function createCounterElement() {
        if (document.getElementById('page-counter-userscript')) return;

        pageCounterElement = document.createElement('div');
        pageCounterElement.id = 'page-counter-userscript';

        // Custom styling for the counter box
        Object.assign(pageCounterElement.style, {
            position: 'fixed',
            bottom: config.counterPosition.bottom,
            left: config.counterPosition.left,
            padding: '5px 7px',
            borderRadius: '0px',
            color: 'rgba(255, 255, 255, 0.5)',          //Adjust 0.X to increase or decrease text brightness
            border: '0.3px solid rgba(1, 1, 12, 1.0)',  //Set 1.0 to 0.0 to hide the border
            backgroundColor: 'rgba(73, 83, 89, 1.0)',   //Set 1.0 to 0.0 to hide the background
            zIndex: '99999',
            fontSize: '17px',
            fontFamily: 'Inter, sans-serif',
            fontWeight: '525',
            pointerEvents: 'none',
        });
        document.body.appendChild(pageCounterElement);
    }

    /**
     * Adjusts the counter's scale to counteract browser zoom, keeping its size constant.
     */
    function adjustForZoom() {
        if (!pageCounterElement) return;
        const zoomLevel = window.devicePixelRatio || 1;
        const scale = 1 / zoomLevel;
        pageCounterElement.style.transform = `scale(${scale})`;
        pageCounterElement.style.transformOrigin = 'bottom left';
    }


    /**
     * Finds the total number of pages ONCE by reading the hidden input field.
     */
    function findAndCacheTotalPages() {
        if (cachedTotalPages !== null) return;
        try {
            const maxPageInput = document.getElementById('max_page');
            if (maxPageInput && maxPageInput.value) {
                cachedTotalPages = parseInt(maxPageInput.value, 10);
            }
        } catch (e) {
            console.error("[Page Counter] Error reading total pages.", e);
        }
    }

    /**
     * Finds the current page number by reading the visible page button.
     */
    function getCurrentPage() {
        try {
            const pageButton = document.querySelector("button[x-text=\"'Page ' + page\"]");
            if (pageButton && pageButton.textContent) {
                const match = pageButton.textContent.match(/(\d+)/);
                if (match && match[1]) {
                    return parseInt(match[1], 10);
                }
            }
        } catch(e) {
            console.error("[Page Counter] Error reading current page.", e);
        }
        return null;
    }

    /**
     * Updates the counter display.
     */
    function updatePageCount() {
        if (!pageCounterElement) return;

        const current = getCurrentPage();
        const total = cachedTotalPages;

        if (current !== null || total !== null) {
            const currentStr = current !== null ? current : '?';
            const totalStr = total !== null ? total : '?';
            pageCounterElement.textContent = `${currentStr}/${totalStr}`;
            pageCounterElement.style.opacity = '1';
        } else {
             pageCounterElement.style.opacity = '0';
        }
    }

    const debouncedUpdate = debounce(updatePageCount, 50);

    function init() {
        createCounterElement();
        adjustForZoom(); // Set the initial scale
        findAndCacheTotalPages();

        const observerTarget = document.querySelector("button[x-text=\"'Page ' + page\"]");
        if (!observerTarget) {
            console.error("[Page Counter] Could not find target page button for observation.");
            updatePageCount(); // Try to update once
            return;
        }

        observer = new MutationObserver(() => {
            debouncedUpdate();
        });

        observer.observe(observerTarget, {
            childList: true,
            subtree: true
        });

        // Listen for resize/zoom events to keep the counter size consistent
        window.addEventListener('resize', debounce(adjustForZoom, 100));

        updatePageCount();
    }

    if (document.readyState === 'complete') {
        init();
    } else {
        window.addEventListener('load', init);
    }
})();