您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
When doing puzzles, this will show you your stats
- // ==UserScript==
- // @name Lichess: Training: Stats for Current Run
- // @version 1.1.0
- // @author pedro-mass
- // @copyright 2024, Pedro Mass (https://github.com/pedro-mass)
- // @description When doing puzzles, this will show you your stats
- // @grant none
- // @icon https://www.google.com/s2/favicons?sz=64&domain=lichess.org
- // @license GNU GPLv3
- // @match https://lichess.org/training/*
- // @match https://lichess.org/training
- // @namespace http://tampermonkey.net/
- // @run-at document-idle
- // ==/UserScript==
- const ids = {
- stats: "pm-stats",
- };
- const selectors = {
- results: ".result-empty",
- stats: `#${ids.stats}`,
- puzzleHolder: ".puzzle__session",
- };
- const constants = {
- failure: "result-false",
- success: "result-true",
- };
- waitForElement(document, selectors.results).then(() => {
- run();
- watchElement(document.querySelector(selectors.puzzleHolder), (changes) => {
- if (wasTextChange(changes)) return;
- run();
- });
- });
- // ------------------
- // helper functions
- // ------------------
- /**
- * @param {MutationRecord[]} changes
- */
- function wasTextChange(changes) {
- if (!changes || changes.length === 0) return;
- const firstChange = changes[0];
- return (
- firstChange.target.id === ids.stats && firstChange.type === "childList"
- );
- }
- // src: https://stackoverflow.com/a/47406751/2911615
- function waitForElement(root, selector) {
- return new Promise((resolve, _reject) => {
- new MutationObserver(check).observe(root, {
- childList: true,
- subtree: true,
- });
- function check(_changes, observer) {
- let element = root.querySelector(selector);
- if (element) {
- observer.disconnect();
- resolve(element);
- }
- }
- });
- }
- function watchElement(root = document, onChange) {
- new MutationObserver(onChange).observe(root, {
- childList: true,
- subtree: true,
- });
- }
- function run() {
- const statsElem = getStatsElem();
- displayFailures(statsElem);
- let showFailures = true;
- statsElem.addEventListener("click", function flipDisplay() {
- showFailures = !showFailures;
- showFailures ? displayFailures(statsElem) : displaySuccesses(statsElem);
- });
- }
- function getResults() {
- return Array.from(document.querySelectorAll(selectors.results));
- }
- function getStatsElem() {
- return document.querySelector(selectors.stats) ?? createStatsElem();
- }
- function createStatsElem() {
- const statsElem = document.createElement("div");
- statsElem.id = ids.stats;
- document.querySelector(selectors.puzzleHolder).appendChild(statsElem);
- return statsElem;
- }
- function getStats() {
- const results = getResults();
- const failures = results.filter((x) =>
- Array.from(x.classList).includes(constants.failure)
- );
- const successes = results.filter((x) =>
- Array.from(x.classList).includes(constants.success)
- );
- return {
- total: results.length,
- failures: failures.length,
- successes: successes.length,
- };
- }
- function displayFailures(elem) {
- const { total, failures } = getStats();
- elem.textContent = `${failures} / ${total} failures`;
- }
- function displaySuccesses(elem) {
- const { total, successes } = getStats();
- elem.textContent = `${successes} / ${total} successes`;
- }