您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Quality buttons toggle: 2160p|4k treated as one unit, remove full unit if present, append after last quality with |, cleans extra |. Works in any order.
当前为
// ==UserScript== // @name DMM Top Filter Buttons // @namespace http://tampermonkey.net/ // @version 1.20 // @description Quality buttons toggle: 2160p|4k treated as one unit, remove full unit if present, append after last quality with |, cleans extra |. Works in any order. // @author Waseem // @match https://debridmediamanager.com/* // @grant none // @run-at document-idle // ==/UserScript== (function() { 'use strict'; function setReactValue(element, value) { const nativeSetter = Object.getOwnPropertyDescriptor( window.HTMLInputElement.prototype, 'value' ).set; nativeSetter.call(element, value); element.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']; function escapeRegex(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // escape special regex chars } 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(`span.${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', () => { let current = input.value.trim(); if (qualityValues.includes(btn.value)) { const clickedQuality = btn.value; // Remove if already present const escaped = escapeRegex(clickedQuality); const regex = new RegExp(`(^|\\||\\s)${escaped}($|\\||\\s)`); if (current.match(regex)) { // Split by spaces to handle each "word group" separately const parts = current.split(' '); const filteredParts = parts.map(part => { // Remove the quality from this part, handling pipe separators const qualityRegex = new RegExp(`(^|\\|)${escaped}($|\\|)`); let cleaned = part.replace(qualityRegex, (match, before, after) => { // If we're removing from middle, preserve the separator if (before === '|' && after === '|') return '|'; // If we're removing from start/end, remove the separator too return ''; }); // Clean up multiple pipes and leading/trailing pipes cleaned = cleaned.replace(/\|{2,}/g, '|').replace(/^\|+|\|+$/g, ''); return cleaned; }).filter(part => part.length > 0); // Remove empty parts current = filteredParts.join(' ').trim(); setReactValue(input, current); return; } // Append after last existing quality let lastFound = null; qualityValues.forEach(q => { const idx = current.lastIndexOf(q); if (idx !== -1) lastFound = { value: q, index: idx }; }); if (lastFound) { const before = current.slice(0, lastFound.index + lastFound.value.length); const after = current.slice(lastFound.index + lastFound.value.length); current = before + '|' + clickedQuality + after; } else { current = current ? current + ' ' + clickedQuality : clickedQuality; } // Clean double | and leading/trailing | current = current.replace(/\|{2,}/g, '|').replace(/^\|+|\|+$/g, ''); current = current.replace(/\s+/g, ' ').trim(); setReactValue(input, current); } else { // Non-quality buttons toggle if (current.includes(btn.value)) { // Use word boundary regex to avoid partial matches const regex = new RegExp(`\\s*\\b${escapeRegex(btn.value)}\\b\\s*`, 'g'); current = current.replace(regex, ' ').trim(); current = current.replace(/\s+/g, ' '); setReactValue(input, current); } else { current = current ? current + ' ' + btn.value : btn.value; setReactValue(input, current); } } }); }); } function setupEscapeClear() { const input = document.querySelector('#query'); if (!input) return; document.addEventListener('keydown', (e) => { if (e.key === 'Escape') setReactValue(input, ''); }); } const observer = new MutationObserver(() => { addFilterButtons(); setupEscapeClear(); }); observer.observe(document.body, { childList: true, subtree: true }); })();