您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a minimum rating filter to anime list on LiveChart.me with styled UI and persistent value
// ==UserScript== // @name LiveChart.me Minimum Rating Filter with Themed UI (Persistent) // @namespace http://tampermonkey.net/ // @version 1.7 // @author pedro-mass // @copyright 2025, Pedro Mass (https://github.com/pedro-mass) // @icon https://www.google.com/s2/favicons?sz=64&domain=livechart.me // @license GNU GPLv3 // @description Adds a minimum rating filter to anime list on LiveChart.me with styled UI and persistent value // @match https://www.livechart.me/* // @run-at document-idle // @grant none // ==/UserScript== (function() { 'use strict'; const STORAGE_KEY = 'pm_min_rating'; init(); function init() { addFilterUI(); } function addFilterUI() { const container = document.querySelector('.options-bar-v2'); if (!container) return; const existingUI = document.querySelector('.pm-rating-filter'); if (existingUI) existingUI.remove(); const label = document.createElement("label"); label.textContent = "Minimum Rating:"; label.classList.add('pm-rating-filter', 'option-v2'); Object.assign(label.style, { display: "flex", gap: "0.5em", alignItems: "center", fontFamily: "sans-serif", fontSize: "0.9em" }); const input = Object.assign(document.createElement("input"), { type: "number", placeholder: "7.6", min: "0", max: "10", step: "0.1", id: "pm-rating-input", value: localStorage.getItem(STORAGE_KEY) || "" }); Object.assign(input.style, { width: "4em", padding: "0.25em 0.35em", border: "1px solid #ccc", borderRadius: "4px", fontSize: "0.9em", transition: "border-color 0.2s", backgroundColor: "#fff" }); label.htmlFor = input.id; label.appendChild(input); const filters = container.querySelectorAll('.option-v2.hide-for-small-only'); const lastFilter = filters[filters.length - 1]; if (!lastFilter) return console.error("Could NOT find the filters to add onto"); lastFilter.after(label); // Input listener input.addEventListener("input", debounce((event) => { const value = toNumber(event.target.value, 0); filterAnimes(value); // Save to localStorage localStorage.setItem(STORAGE_KEY, value); }, 300)); // Apply filter on page load if a value is saved const savedValue = toNumber(localStorage.getItem(STORAGE_KEY), 0); if (savedValue > 0) { filterAnimes(savedValue); } } function filterAnimes(minRating = 0) { const animes = document.querySelectorAll('.anime'); animes.forEach(anime => { const rating = parseFloat(anime.querySelector('.anime-avg-user-rating')?.innerText) || 0; if (rating < minRating) { hide(anime); } else { show(anime); } }); } function debounce(func, delay) { let timeoutId; return function(...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; } function toNumber(input, defaultValue = 0) { const number = parseFloat(input); return Number.isNaN(number) ? defaultValue : number; } function hide(element) { element.style.display = "none"; } function show(element) { element.style.display = ""; } })();