DMM - All Results & Polish Filter

Adds a "Show All Results" button and a Polish filter button to Debrid Media Manager.

// ==UserScript==
// @name         DMM - All Results & Polish Filter
// @namespace    http://tampermonkey.net/
// @version      4.2
// @description  Adds a "Show All Results" button and a Polish filter button to Debrid Media Manager.
// @author       Your Assistant & tomfle
// @match        *://*.debridmediamanager.com/movie/*
// @match        *://*.debridmediamanager.com/show/*/*
// @grant        none
// @run-at       document-idle
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // --- SETTINGS AND GLOBAL VARIABLES ---
    const SHOW_ALL_BUTTON_ID = 'show-all-results-btn';
    const POLISH_FILTER_BUTTON_ID = 'polish-filter-btn';
    const CHECK_INTERVAL = 500; // Time in ms, how often the script checks for a new button

    // This regex is for finding Polish language releases. The keywords are names of Polish release groups or common terms.
    const POLISH_REGEX = String.raw`(\b(adl|agusiq|al3x|ale13|alusia|as76|azjatycki|azq|b89|bida|chrisvps|d11|denda|dsite|elladajarek|emis|enter1973|esperanza|eteam|feld|fiona9|gamer158|ghn|gr4pe|h3q|hmdb|intgrity|j60|joanna668|k83|kit|kolekcja|komplet|kpfr|ksq|lektor|ltn|m80|marcin0313|maxim|mg|mixio|mowy|napiproject|napisy|napisypl|nn|nonano|noq|ozw|p2p|paczka|pl|pl_1080p_web|pldub|plsub|pol|polish|psig|r22|r68|ralf|robsil|rx|s56|sezonów|sezonow|sezony|sfpi|sharpe|sk13|spajk85|spedboy|starlord|starlordx|superseed|syntezator|syrix|tfsh|tłumacz|toalien|topfilmyfilmweb|torrentmaniak|vantablack|wasik|wilu75|wersja|xupload|zbyszek|electro-torrent|devil-torrents|polskie-torrenty|cool-torents|ex-torrenty)\b)|(ą|ć|ę|ł|ń|ś|ź|ż)`;
    const POLISH_FILTER_BUTTON_TEXT = '🇵🇱';

    // --- FUNCTIONS FOR "SHOW ALL RESULTS" BUTTON ---

    function findShowMoreButton() {
        const buttons = Array.from(document.querySelectorAll('button'));
        return buttons.find(button =>
            button.textContent?.trim() === 'Show More Results' &&
            button.offsetParent !== null
        ) || null;
    }

    function waitForNextButton() {
        return new Promise((resolve) => {
            const maxAttempts = 20; // Max 10 seconds
            let attempts = 0;
            const interval = setInterval(() => {
                const button = findShowMoreButton();
                if (button) {
                    clearInterval(interval);
                    resolve(button);
                } else if (++attempts >= maxAttempts) {
                    clearInterval(interval);
                    resolve(null);
                }
            }, CHECK_INTERVAL);
        });
    }

    async function fetchAllResults(showAllButton) {
        let pageCount = 1;
        showAllButton.textContent = `Loading page ${pageCount}...`;
        showAllButton.disabled = true;

        let showMoreButton = findShowMoreButton();
        while (showMoreButton) {
            showMoreButton.click();
            showMoreButton.style.display = 'none';
            showMoreButton = await waitForNextButton();
            if (showMoreButton) {
                pageCount++;
                showAllButton.textContent = `Loading page ${pageCount}...`;
            }
        }

        showAllButton.textContent = 'All results loaded';
        showAllButton.style.borderColor = '#22c55e';
        showAllButton.style.backgroundColor = 'rgba(34, 197, 94, 0.3)';
        showAllButton.style.color = '#dcfce7';
        showAllButton.style.fontWeight = 'bold'; // Set font to bold
        showAllButton.disabled = true;
    }

    function createShowAllButton() {
        if (!findShowMoreButton() || document.getElementById(SHOW_ALL_BUTTON_ID)) {
            return;
        }

        const buttons = Array.from(document.querySelectorAll('button'));
        const showRelatedButton = buttons.find(b => b.textContent?.includes('Show Related'));
        if (!showRelatedButton || !showRelatedButton.parentNode) {
            return;
        }
        const targetContainer = showRelatedButton.parentNode;

        const showAllButton = document.createElement('button');
        showAllButton.textContent = 'Show All Results';
        showAllButton.id = SHOW_ALL_BUTTON_ID;
        showAllButton.className = showRelatedButton.className;
        showAllButton.style.marginLeft = '0.5rem';
        showAllButton.style.fontWeight = 'bold'; // Set font to bold

        showAllButton.addEventListener('click', (e) => {
            e.preventDefault();
            e.stopPropagation();
            fetchAllResults(showAllButton);
        });

        targetContainer.appendChild(showAllButton);
    }

    // --- FUNCTIONS FOR POLISH FILTER BUTTON ---

    function createPolishFilterButton() {
        const filterInput = document.querySelector('input#query');
        const buttonContainer = document.querySelector('.flex.items-center.gap-2.overflow-x-auto');

        if (filterInput && buttonContainer && !buttonContainer.querySelector(`#${POLISH_FILTER_BUTTON_ID}`)) {
            const newButton = document.createElement('button');
            newButton.id = POLISH_FILTER_BUTTON_ID;
            newButton.textContent = POLISH_FILTER_BUTTON_TEXT;
            newButton.className = 'cursor-pointer whitespace-nowrap rounded border border-cyan-500 bg-transparent px-2 py-1 text-xs text-blue-100 transition-colors hover:bg-cyan-900/50';
            newButton.style.order = '-1'; // Sets the button as the first one

            newButton.addEventListener('click', function() {
                // This method is needed to correctly update the value in React applications
                const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
                    window.HTMLInputElement.prototype,
                    'value'
                ).set;
                nativeInputValueSetter.call(filterInput, POLISH_REGEX);

                // Simulate an input event so React notices the change
                const inputEvent = new Event('input', { bubbles: true, cancelable: true });
                filterInput.dispatchEvent(inputEvent);
            });

            buttonContainer.prepend(newButton);
        }
    }

    // --- MAIN LOGIC AND OBSERVER ---

    function initializeButtons() {
        createShowAllButton();
        createPolishFilterButton();
    }

    const observer = new MutationObserver((mutationsList, obs) => {
        // The initializeButtons function has built-in safeguards,
        // so it can be safely called multiple times.
        initializeButtons();
    });

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

    // Run the function once at the beginning, just in case
    setTimeout(initializeButtons, 1500);
})();