您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a sidebar where you can filter your searches on Roblox.
// ==UserScript== // @name 🔎 Roblox Search Filters v1.0.0 // @namespace http://tampermonkey.net/ // @version 1.0.0 // @description Adds a sidebar where you can filter your searches on Roblox. // @author ru-bem // @match https://www.roblox.com/discover/* // @match https://www.roblox.com/charts/* // @license GPL-3.0-or-later // @grant none // ==/UserScript== (function() { 'use strict'; //// Personalization const config={ interfacePosition:{top:'80px',left:'0'}, interfaceStyles:{ position:'fixed', backgroundColor:'#191a1f', border:'0px solid #222', padding:'50px 15px 300px 15px', borderRadius:'16px', zIndex:'9999', fontFamily:'Arial, sans-serif', cursor:'grab', boxShadow:'0 10px 10px rgba(0,0,0,0)' }, layout:{ groupDirection:'vertical', inputAlignment:'rows', spacing:{betweenGroups:'30px',betweenInputs:'5px'} }, elementsOrder:['approval','players','button'], inputStyles:{ width:'74px',padding:'5px',margin:'0',borderRadius:'0px', backgroundColor:'#222',color:'white',border:'0px solid #333' }, buttonStyles:{ width:'100%',backgroundColor:'#335fff',color:'white', padding:'12px 0',border:'none',borderRadius:'6px', cursor:'pointer',marginTop:'15px',fontWeight:'bold' }, defaultFilters:{minApproval:80,maxApproval:100,minPlayers:'',maxPlayers:''}, selectors:{ gameCard:['.game-card-container','.list-item.game-card.game-tile'], approvalPercentage:'.vote-percentage-label', activePlayers:'.playing-counts-label' }, urlKeywords:['/discover/?Keyword=','/charts/'] }; //// Code function createInterface(){ if(document.getElementById('approval-filter-interface')) return; const interfaceDiv = document.createElement('div'); interfaceDiv.id = 'approval-filter-interface'; Object.assign(interfaceDiv.style, config.interfaceStyles); interfaceDiv.style.top = config.interfacePosition.top; interfaceDiv.style.left = config.interfacePosition.left; // Groups const groups = { approval: createFilterGroup('👍 %Approval', 'minApproval', 'maxApproval'), players: createFilterGroup('▶️ Active Players', 'minPlayers', 'maxPlayers'), button: createButton() }; // Order elements config.elementsOrder.forEach(key => { if(groups[key]) { groups[key].style.marginBottom = config.layout.spacing.betweenGroups; interfaceDiv.appendChild(groups[key]); } }); document.body.appendChild(interfaceDiv); makeDraggable(interfaceDiv); function createFilterGroup(title, minKey, maxKey) { const group = document.createElement('div'); const titleElement = document.createElement('div'); titleElement.textContent = title; titleElement.style.color = '#fff'; titleElement.style.marginBottom = '10px'; const inputsContainer = document.createElement('div'); inputsContainer.style.display = 'flex'; inputsContainer.style.flexDirection = 'column'; inputsContainer.style.gap = config.layout.spacing.betweenInputs; const minInput = createInput('number', config.defaultFilters[minKey], 'MIN:'); const maxInput = createInput('number', config.defaultFilters[maxKey], 'MAX:'); inputsContainer.append(minInput, maxInput); group.append(titleElement, inputsContainer); group.minInput = minInput.querySelector('input'); group.maxInput = maxInput.querySelector('input'); return group; } function createInput(type, value, labelText) { const container = document.createElement('div'); container.style.display = 'flex'; container.style.alignItems = 'center'; container.style.gap = '10px'; const label = document.createElement('label'); label.textContent = labelText; label.style.color = '#ccc'; label.style.minWidth = '60px'; const input = document.createElement('input'); input.type = type; input.value = value; Object.assign(input.style, config.inputStyles); container.append(label, input); return container; } function createButton() { const button = document.createElement('button'); button.textContent = 'Filter'; Object.assign(button.style, config.buttonStyles); button.onclick = () => { filterGames( parseInt(groups.approval.minInput.value) || 0, parseInt(groups.approval.maxInput.value) || 100, parseInt(groups.players.minInput.value) || 0, parseInt(groups.players.maxInput.value) || Infinity ); }; return button; } } function filterGames(minApproval, maxApproval, minPlayers, maxPlayers) { document.querySelectorAll(config.selectors.gameCard).forEach(card => { const approvalMatch = checkApproval(card, minApproval, maxApproval); const playersMatch = checkPlayers(card, minPlayers, maxPlayers); card.style.display = (approvalMatch && playersMatch) ? '' : 'none'; }); function checkApproval(card, min, max) { const element = card.querySelector(config.selectors.approvalPercentage); if (!element) return true; const percent = parseInt(element.textContent.replace(/\D/g, '')); return percent >= min && percent <= max; } function checkPlayers(card, min, max) { const element = card.querySelector(config.selectors.activePlayers); if (!element) return true; const players = parseInt(element.textContent.replace(/\D/g, '')); return players >= min && players <= max; } } function makeDraggable(element) { let isDragging = false; let offset = [0, 0]; element.addEventListener('mousedown', e => { if (e.target.tagName === 'INPUT') return; isDragging = true; offset = [e.clientX - element.offsetLeft, e.clientY - element.offsetTop]; element.style.cursor = 'grabbing'; }); document.addEventListener('mousemove', e => { if (!isDragging) return; element.style.left = `${e.clientX - offset[0]}px`; element.style.top = `${e.clientY - offset[1]}px`; }); document.addEventListener('mouseup', () => { isDragging = false; element.style.cursor = 'grab'; }); } // Init new MutationObserver(() => { if (config.urlKeywords.some(kw => location.href.includes(kw))) { createInterface(); } }).observe(document.body, { subtree: true, childList: true }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址