Last active
January 26, 2026 12:19
-
-
Save vimaexd/b796ead270345a1173c52b3310936ab9 to your computer and use it in GitHub Desktop.
adds a search box to Zenius -I- Vanisher's arcade page to search for game series' faster
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name ZIV arcade search box | |
| // @namespace Violentmonkey Scripts | |
| // @match https://zenius-i-vanisher.com/v5.2/arcades.php* | |
| // @grant none | |
| // @version 1.0 | |
| // @author vimae (mae@mae.wtf) | |
| // @description 22/01/2026, 13:56:06 | |
| // @downloadURL https://gist.github.com/vimaexd/b796ead270345a1173c52b3310936ab9/raw/34e352e1a18eb1dd12e27e9c958443081114eb6d/zivsearch.user.js | |
| // ==/UserScript== | |
| const seriesSelector = document.querySelector("#search-series"); | |
| const series = {}; | |
| const seriesNames = []; | |
| const hardcodedMatches = { | |
| "sdvx": "SOUND VOLTEX", | |
| "ddr": "DanceDanceRevolution", | |
| "smx": "StepManiaX", | |
| "itg": "in the groove", | |
| "piu": "Pump It Up", | |
| "museca": "MÚSECA", | |
| "pnm": "pop'n music" | |
| } | |
| if(!seriesSelector) { | |
| console.log("[searchbox] series selector not found") | |
| } | |
| // populate series | |
| [...seriesSelector.children].forEach(o => { | |
| series[o.innerText] = o.value | |
| seriesNames.push(o.innerText) | |
| }) | |
| // add searchbox and dropdown | |
| seriesSelector.parentElement.insertAdjacentHTML("beforeend", `<br/><input id="series-search" type="text" placeholder="Type name of series" style="margin-top: 4px;"/>`) | |
| seriesSelector.parentElement.insertAdjacentHTML("beforeend", ` | |
| <div style="position: relative;"> | |
| <style> | |
| #series-dropdown { | |
| position: absolute; | |
| background: white; | |
| padding: 2px 2px; | |
| border: 1px solid black; | |
| margin-top: 2px; | |
| width: 320px; | |
| box-shadow: 0px 2px 8px rgba(0,0,0,0.4); | |
| box-sizing: border-box; | |
| } | |
| #series-dropdown p { | |
| margin: 0; | |
| padding: 4px 4px; | |
| width: 100%; | |
| cursor: pointer; | |
| box-sizing: border-box; | |
| } | |
| #series-dropdown p:not(:last-of-type) { | |
| border-bottom: 1px solid grey; | |
| } | |
| #series-dropdown p:hover { | |
| background: rgba(0,0,0,0.2) | |
| } | |
| </style> | |
| <div id="series-dropdown" style="visibility: hidden;"> | |
| </div> | |
| </div> | |
| `); | |
| // resolve partial alias (eg. "sd" -> SOUND VOLTEX) | |
| function resolveAliases(query) { | |
| return Object.entries(hardcodedMatches) | |
| .filter(([alias]) => alias.startsWith(query)) | |
| .map(([, value]) => value.toLowerCase()) | |
| } | |
| // ranks search results inclusive of aliases and partial matches | |
| function searchScore(str, query) { | |
| str = str.toLowerCase() | |
| query = query.toLowerCase() | |
| const aliases = resolveAliases(query) | |
| const candidates = [query, ...aliases] | |
| let bestScore = 999 | |
| for (const q of candidates) { | |
| let score = 3 | |
| if (str === q) score = 0 | |
| else if (str.startsWith(q)) score = 1 | |
| else if (str.includes(q)) score = 2 | |
| bestScore = Math.min(bestScore, score) | |
| } | |
| return 3 | |
| } | |
| // handle search box typing | |
| document.querySelector("#series-search") | |
| .addEventListener("input", (e) => { | |
| if(!e.target.value) { | |
| document.querySelector("#series-dropdown").innerHTML = ""; | |
| document.querySelector("#series-dropdown").style.visibility = "hidden"; | |
| return; | |
| } else { | |
| document.querySelector("#series-dropdown").style.visibility = "visible"; | |
| } | |
| const results = seriesNames | |
| .filter( | |
| s => (s.toLowerCase().includes(e.target.value.toLowerCase()) || resolveAliases(e.target.value).some(a => s.toLowerCase().includes(a))) | |
| ) | |
| .sort((a, b) => searchScore(a, e.target.value.toLowerCase()) - searchScore(b, e.target.value.toLowerCase())) | |
| .splice(0, 8); | |
| document.querySelector("#series-dropdown").innerHTML = results.map(r => | |
| (`<p aria-role="button">${r}</p>`) | |
| ).join("") | |
| let seriesEl = [...document.querySelectorAll("#series-dropdown p")]; | |
| // handle dropdown series click | |
| seriesEl.forEach(s => { | |
| s.addEventListener("click", () => { | |
| document.querySelector("#series-search").value = ""; | |
| document.querySelector("#series-dropdown").innerHTML = ""; | |
| document.querySelector("#series-dropdown").style.visibility = "hidden"; | |
| document.querySelector("#search-series").value = series[s.innerText]; | |
| window.updateGameDropDown(); | |
| }) | |
| }) | |
| }) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment