DMM Top Filter Buttons

Quality buttons append after last found quality with |, ignore duplicates, works in any click order, checks entire input string.

目前為 2025-08-22 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         DMM Top Filter Buttons
// @namespace    http://tampermonkey.net/
// @version      1.17
// @description  Quality buttons append after last found quality with |, ignore duplicates, works in any click order, checks entire input string.
// @author       Waseem
// @match        https://debridmediamanager.com/*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    // Utility to update React-controlled input
    function setReactValue(input, value) {
        const setter = Object.getOwnPropertyDescriptor(
            HTMLInputElement.prototype, 'value'
        ).set;
        setter.call(input, value);
        input.dispatchEvent(new Event('input', { bubbles: true }));
    }

    const buttons = [
        { text: 'instantRD',    value: 'videos:>0',            class: 'dmm-instantrd' },
        { text: '4K',           value: '2160p|4k',             class: 'dmm-4k' },
        { text: '1080p',        value: '1080p',                class: 'dmm-1080p' },
        { text: '720p',         value: '720p',                 class: 'dmm-720p' },
        { text: 'Dolby Vision', value: 'dovi|dv|dolby|vision', class: 'dmm-dolbyvision' },
        { text: 'HDR',          value: 'hdr',                  class: 'dmm-hdr' },
        { text: 'Remux',        value: 'remux',                class: 'dmm-remux' }
    ];

    const qualityValues = ['2160p|4k', '1080p', '720p'];

    // Add buttons to the top filter container
    function addFilterButtons() {
        const container = document.querySelector('#__next > div > div.mb-2.flex.items-center.gap-2.overflow-x-auto.p-2 > div');
        const input = document.querySelector('#query');
        if (!container || !input) return;

        buttons.slice().reverse().forEach(btn => {
            if (container.querySelector(`.${btn.class}`)) return;

            const span = document.createElement('span');
            span.textContent = btn.text;
            span.className = `${btn.class} cursor-pointer whitespace-nowrap rounded border border-blue-500 bg-blue-900/30 px-2 py-0.5 text-xs text-blue-100 transition-colors hover:bg-blue-800/50`;

            container.insertBefore(span, container.firstChild);

            span.addEventListener('click', () => {
                const current = input.value.trim();
                if (current.includes(btn.value)) return; // Avoid duplicates

                if (qualityValues.includes(btn.value)) {
                    // Find last existing quality
                    let lastQualityIndex = -1;
                    let lastQuality = '';
                    qualityValues.forEach(q => {
                        const idx = current.lastIndexOf(q);
                        if (idx > lastQualityIndex) {
                            lastQualityIndex = idx;
                            lastQuality = q;
                        }
                    });

                    if (lastQualityIndex !== -1) {
                        // Append after last quality with |
                        const before = current.slice(0, lastQualityIndex + lastQuality.length);
                        const after = current.slice(lastQualityIndex + lastQuality.length);
                        setReactValue(input, before + '|' + btn.value + after);
                    } else {
                        // No existing quality, append with space
                        setReactValue(input, current ? current + ' ' + btn.value : btn.value);
                    }
                } else {
                    // Non-quality buttons, append with space
                    setReactValue(input, current ? current + ' ' + btn.value : btn.value);
                }
            });
        });
    }

    // Clear input on Escape key
    function setupEscapeClear() {
        const input = document.querySelector('#query');
        if (!input) return;
        document.addEventListener('keydown', (e) => {
            if (e.key === 'Escape') setReactValue(input, '');
        });
    }

    // Observe DOM changes and attach buttons
    const observer = new MutationObserver(() => {
        addFilterButtons();
        setupEscapeClear();
    });
    observer.observe(document.body, { childList: true, subtree: true });

})();