Quality buttons append after last found quality with |, ignore duplicates, works in any click order, checks entire input string.
目前為
// ==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 });
})();