DMM - All Results & Polish Filter

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

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         DMM - All Results & Polish Filter
// @namespace    http://tampermonkey.net/
// @version      5.3
// @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(-ft|-ok|3d11|a4o|adl|afo|agusiq|al3x|ale13|alusia|anonim|as76|azjatycki|azq|b89|best-torrents|bida|bigbbs|bird|bodzio|bp007|brx|cambio|chopin|chrisvps|cinemaet|colo|cool-torents|cru|d11|dabrjarek|deix|denda|dream|dsite|dubbpl|dzidek|eend|electro-torrent|elladajarek|emis|enter1973|esperanza|eteam|evil-bad|evil-torrents|ex-torrenty|feld|filetracker|fiona9|fpl|gamer158|ghn|ghw|gr4pe|gun|h3q|hen|hmdb|ht|intgrity|izyk|j25|j60|joanna668|k041|k12|k37|k8|k83|kbuso|kde|kiko|kilkr|kit|klio|kolekcja|kpfr|krt|ksq|lektor|lektorpl|lex|limit|llo|ltn|lts|lysol1|m56|m80|maksim80|marcin0313|marjos83|maxim|maxx|miniserial|mins|mixio|mors|mr|n0b0dy|n0l4|napiproject|napisy|napisypl|neo|nicollubin|nine|nitroteam|nn|nonano|noq|odc|odcinek|odison|ozw|p2p|paczka|pdlg|pirateszone|pixi|pl|pl_1080p_web|pldub|plsub|plsubbed|pol|polish|polski|polskie-torrenty|polskipl|presa|psig|psotnik|ptrg|r22|r68|ralf|raven|rekonstrukcja|robsil|rx|s56|sav|sezon|sfpi|shadows-torrents|sharpe|sk13|snoop|spajk85|spedboy|starlord|starlordx|superseed|sy5ka|syntezator|syrix|taboon1|tds|tfsh|toalien|top2p|topfilmyfilmweb|torrentmaniak|torrenty|vantablack|wasik|wersja|wilu|wilu75|wizards|wosiu|xte|xtorrenty|xupload|zbyszek|zet|zyl|rip+by+raptcat|ekipa+tnt)\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 events so React notices the change
				const inputEvent = new Event('input', { bubbles: true, cancelable: true });
				const changeEvent = new Event('change', { bubbles: true, cancelable: true }); // <-- DODANE

				filterInput.focus(); // <-- DODANE
				filterInput.dispatchEvent(inputEvent);
				filterInput.dispatchEvent(changeEvent); // <-- DODANE
				filterInput.blur(); // <-- DODANE
            });

            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);
})();