您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Avatar checklist for Grundo's Cafe, visit https://www.grundos.cafe/~Milk
// ==UserScript== // @name Grundo's Cafe Avatar Checklist // @namespace https://www.grundos.cafe/ // @version 1.1 // @description Avatar checklist for Grundo's Cafe, visit https://www.grundos.cafe/~Milk // @author soupfaerie, supercow64 // @match https://www.grundos.cafe/~Milk* // @match https://www.grundos.cafe/~milk* // @match https://www.grundos.cafe/~MILK* // @icon https://www.grundos.cafe/static/images/favicon.66a6c5f11278.ico // @grant none // @license MIT // ==/UserScript== const textToHTML = (text) => new DOMParser().parseFromString(text, "text/html"); /** * Analyse the HTML select element for a list of avatars the user has collected. * * @param {Node} node The root node (default: document) * @returns {string[]} the list of avatars as an array of basenames */ const getCollectedAvatars = (node = doument) => { // The list of avatars is partitioned into default avatars // and collected secret avatas. The option with the text --- // (6 dashes) is the inclusive cutoff. All avatars at and below // the cutoff are collected secret avatars const allAvatars = Array.from( node.querySelectorAll(`[name="new_avatar"] option`) ); const i = allAvatars.findIndex((e) => e.textContent.includes("---")); return allAvatars.slice(i).map((e) => e.value); }; /** * Returns a Promise that resolves to a listo f avatars * the user has collected. * * @returns {string[]} list of collected avatars */ const getCollectedAvatarsAsync = () => fetch("/neoboards/preferences/") .then((res) => res.text()) .then(textToHTML) .then(getCollectedAvatars); /** * Analyse the list of avatars presented on the page ~milk. * * @param {*} node Node * @returns {{ node: Node, src: string}[]} an array of objects with two entries, * where `node` is the DOM node of the list element and `src` is the complete * image URL of the avatar */ const getAvatarsOnPage = (node = document) => Array.from(node.querySelectorAll("ul.imglist")).map((e) => ({ node: e, src: e.querySelector("img").src, })); /** * For static assets, returns the basename of the asset indicated * in the url. * * ```js * basename("https://example.com/foo/bar/baz.gif") == "baz.gif" * ``` * * @param {string} url path to the file with slashes * @returns {string} the basename */ const basename = (url) => url.split("/").slice(-1)[0]; const html = ` <h3 style="order:-1">Not collected</h3> <h3 style="order:3">Collected</h3> <style> div.imglist { display: flex; flex-flow: column nowrap;} [data-collected] { order: 4; } div.imglist center { order: 5 } </style> `; function main(collectedAvatars) { // set up DOM const root = document.querySelector("div.imglist"); root.insertAdjacentHTML("beforeend", html); getAvatarsOnPage().forEach(({ node, src }) => { if (collectedAvatars.includes(basename(src))) { node.dataset.collected = ""; } }); } // You can save a list of basenames in sessionStorage for testing, otherwise // the script fetches live data from your Neoboard settings const debugData = sessionStorage["__debug_list_of_avatars"]; if (debugData) { main(JSON.parse(debugData)); } else { getCollectedAvatarsAsync().then(main); }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址