Study Lichess

Plays random chapters from a study

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name     Study Lichess
// @description Plays random chapters from a study
// @license public domain
// @version  1
// @namespace jlxip
// @grant    none
// @include  https://lichess.org/study/*
// @include  https://lichess.org/study/*/*
// ==/UserScript==

// Source: https://stackoverflow.com/a/12646864/23750873
function shuffleArray(array) {
    for (let i = array.length - 1; i >= 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
    }
}

// Source: https://stackoverflow.com/a/61511955/23750873
function waitForElm(selector) {
    return new Promise(resolve => {
        if (document.querySelector(selector)) {
            return resolve(document.querySelector(selector));
        }

        const observer = new MutationObserver(mutations => {
            if (document.querySelector(selector)) {
                observer.disconnect();
                resolve(document.querySelector(selector));
            }
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    });
}

// ---

let chapters = null;
const exercises = [];

// Waits for something to have the class "active"
function waitActive(x, f, cb) {
  	setTimeout(() => {
      	let e = x;
      	if (typeof(x) === "function")
          	e = x();

      	if (e.classList.contains("active")) {
          	cb();
        } else {
          	if (f != null)
          			f(e);
          	waitActive(x, f, cb);
        }
    }, 10);
}

function play() {
  	if (exercises.length == 0) {
      	alert("🎉");
      	return;
    }
  
		const e = exercises.pop();
  	chapters[e].click();
  
  	// Wait for chapter to become active
  	waitActive(chapters[e], null, () => {
      	// Click preview button (repeatedly until it works)
      	waitActive(() => document.getElementsByClassName("preview")[0], x => x.click(), () => {
          	// That's it, wait for solve
            waitForElm(".retry").then(play);
        });
    });
}

waitForElm(".study__side").then((x) => {
    const but = document.createElement("span");
		but.classList.add("more");
		but.classList.add("narrow");
		but.setAttribute("data-icon", "🧐");

		but.onclick = () => {
        // Get exercises
        chapters = document.getElementsByClassName("study__chapters")[0].children;
        for (let i=0; i<chapters.length - 1; ++i)
          	exercises.push(i);

      	// Shuffle
        shuffleArray(exercises);

      	// Play the first
      	play();
		};

		x.children[0].append(but);
});