Extra Study: Audio Quiz

Adds the option to change the WK extra study to audio => meaning questions.

目前為 2022-03-22 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Extra Study: Audio Quiz
// @namespace    extraStudyAudioQuiz
// @version      1.4
// @description  Adds the option to change the WK extra study to audio => meaning questions.
// @author       Sinyaven
// @license      MIT-0
// @match        https://www.wanikani.com/
// @match        https://www.wanikani.com/dashboard
// @match        https://www.wanikani.com/extra_study/session*
// @match        https://preview.wanikani.com/
// @match        https://preview.wanikani.com/dashboard
// @match        https://preview.wanikani.com/extra_study/session*
// @require      https://gf.qytechs.cn/scripts/441518-wanikani-queue-manipulator/code/WaniKani%20Queue%20Manipulator.js?version=1029770
// @run-at       document-start
// @grant        none
// ==/UserScript==

(function() {
	"use strict";
	/* global $, wkof, wkQueueManipulator */
	/* eslint no-multi-spaces: off */

	let lastItemKey = "";

	if (document.URL.includes("extra_study/session")) {
		if (localStorage.getItem("extraStudyAudioQuiz") !== "true") return;
		onlyVocabQuestions();
		onlyMeaningQuestions();
		turnAllIntoAudioQuestions();
		addAudioHotkey();
	} else {
		addToggle();
		deleteAllHalfFinishedQuestions();
	}

	function onlyVocabQuestions() {
		wkQueueManipulator.filter.push(onlyVocab);
	}

	async function onlyMeaningQuestions() {
		await wkQueueManipulator.jQueryReady();
		$.jStorage.listenKeyChange("questionType", () => {
			if ($.jStorage.get("questionType") !== "meaning") $.jStorage.set("questionType", "meaning");
		});
		$.jStorage.listenKeyChange("currentItem", () => {
			const item = $.jStorage.get("currentItem");
			const currentItemKey = `e/stats/${item.type[0].toLowerCase()}${item.id}`;
			if (currentItemKey === lastItemKey) return;
			$.jStorage.deleteKey(lastItemKey);
			$.jStorage.set(currentItemKey, {rc: 1});
			lastItemKey = currentItemKey;
		});
	}

	async function turnAllIntoAudioQuestions() {
		await wkQueueManipulator.domReady();
		addStudyCss();
		const character = document.getElementById("character");
		const icon = document.createElement("i");
		icon.classList.add("fa", "fa-volume-up");
		character.lastElementChild.after(icon);
		character.addEventListener("click", playAudio);
		new MutationObserver(m => {
			const answered = m[0].target.classList.contains("correct") || m[0].target.classList.contains("incorrect");
			document.body.classList.toggle("answered", answered);
			if (!answered) playAudio();
		}).observe(document.querySelector("#answer-form fieldset"), {attributes: true, attributeFilter: ["class"]});
	}

	async function deleteAllHalfFinishedQuestions() {
		await wkQueueManipulator.jQueryReady();
		$.jStorage.index().forEach(key => {
			if (key.startsWith("e/stats/")) $.jStorage.deleteKey(key);
		});
	}

	async function addToggle() {
		const [input, label] = createSwitch("audio-quiz-switch", "Audio Quiz");
		input.checked = localStorage.getItem("extraStudyAudioQuiz") === "true";
		input.addEventListener("change", e => localStorage.setItem("extraStudyAudioQuiz", e.target.checked));
		await wkQueueManipulator.domReady();
		addDashboardCss();
		(await wkQueueManipulator.domElementAvailable(document.getElementsByClassName("extra-study")[0], "div")).after(input, label);
	}

	function createSwitch(id, text) {
		const input = document.createElement("input");
		const label = document.createElement("label");
		input.type = "checkbox";
		input.id = id;
		label.htmlFor = id;
		label.textContent = text;
		label.classList.add("switch");
		input.classList.add("switch");
		return [input, label];
	}

	async function onlyVocab(list) {
		if (!window.wkof) {
			alert("Extra Study: Audio Quiz script requires Wanikani Open Framework.");
			return list;
		}

		wkof.include("ItemData");
		await wkof.ready("ItemData");
		const vocab = await wkof.ItemData.get_items({wk_items: {filters: {item_type: "voc"}}});
		const vocIds = vocab.reduce((result, item) => ((result.add(item.id), result)), new Set());
		return list.filter(id => vocIds.has(id));
	}

	function addAudioHotkey() {
		document.addEventListener("keydown", e => {
			if ((e.ctrlKey || e.altKey) && e.key === "j") {
				e.preventDefault();
				e.stopPropagation();
				playAudio();
			}
		});
	}

	function playAudio() {
		document.getElementById("option-audio-player").click();
	}

	function addDashboardCss() {
		const style = document.createElement("style");
		style.textContent = `
		.extra-study {
			position: relative;
		}

		input.switch {
			display: none;
		}

		.extra-study label.switch {
			position: absolute;
			right: 12px;
			top: 16px;
		}

		label.switch {
			padding-right: 2.1em;
		}

		label.switch::before {
			content: "";
			position: absolute;
			top: 0.18em;
			right: 0;
			width: 1.7em;
			height: 1em;
			border-radius: 1em;
			background-color: #bdbdbd;
			transition: .2s;
		}

		label.switch::after {
			content: "";
			position: absolute;
			top: 0.18em;
			right: 0;
			width: 1em;
			height: 1em;
			border-radius: 50%;
			background-color: white;
			transition: .2s;
			transform: translateX(-0.7em) scale(0.8);
		}

		input.switch:checked + label::before {
			background-color: #59c274;
		}

		input.switch:checked + label::after {
			transform: scale(0.8);
		}

		.es-mover label.switch {
			right: 36px;
		}

		.es-mover-minimal label.switch {
			top: auto;
			right: 12px;
			bottom: 0;
		}`;
		document.head.appendChild(style);
	}

	function addStudyCss() {
		const style = document.createElement("style");
		style.textContent = `
		#character {
			cursor: pointer;
		}

		#character span {
			display: inline-block;
			width: 0;
			opacity: 0;
			white-space: nowrap;
		}

		body.answered #character i {
			display: none;
		}

		body.answered #character span {
			width: initial;
			opacity: initial;
		}`;
		document.head.appendChild(style);
	}
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址