WaniKani Answer Checker

Modifiable answer checker in reviews and lessons

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.gf.qytechs.cn/scripts/470201/1215595/WaniKani%20Answer%20Checker.js

  1. // ==UserScript==
  2. // @name WaniKani Answer Checker
  3. // @namespace http://www.wanikani.com
  4. // @version 0.1.0
  5. // @description Modifiable answer checker in reviews and lessons
  6. // @author polv
  7. // @match https://www.wanikani.com/*
  8. // @match https://preview.wanikani.com/*
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=wanikani.com
  10. // @license MIT
  11. // @source https://github.com/patarapolw/wanikani-userscript/blob/master/userscripts/answer-checker.user.js
  12. // @grant none
  13. // ==/UserScript==
  14.  
  15. // @ts-check
  16. /// <reference path="./types/answer-checker.d.ts" />
  17. (function () {
  18. class ModAnswerChecker {
  19. /**
  20. * @type {TryEvaluationFunction[]}
  21. */
  22. mods = [];
  23. /**
  24. * @type {{
  25. * oldEvaluate?: EvaluationFunction
  26. * evaluate: EvaluationFunction
  27. * } | null}
  28. */
  29. answerChecker = null;
  30.  
  31. /**
  32. *
  33. * @param {TryEvaluationFunction} fn
  34. */
  35. register(fn) {
  36. this.mods.push(fn);
  37. }
  38.  
  39. constructor() {
  40. // Automatically init on new instance
  41. window.addEventListener('turbo:load', (e) => {
  42. // @ts-ignore
  43. const url = e.detail.url;
  44. if (!url) return;
  45.  
  46. /**
  47. * e.g.
  48. * https://www.wanikani.com/subjects/lesson/quiz?queue=${subjectIds.join('-')}
  49. * https://www.wanikani.com/subjects/review
  50. * https://www.wanikani.com/subjects/extra_study?queue_type=${queueType}
  51. */
  52. if (/(session|quiz|review|extra_study)/.test(url)) {
  53. // @ts-ignore
  54. const Stimulus = window.Stimulus;
  55. if (!Stimulus) return;
  56.  
  57. const startDate = +new Date();
  58. const intervalId = setInterval(() => {
  59. this.answerChecker =
  60. Stimulus.controllers.find((x) => {
  61. return x.answerChecker;
  62. })?.answerChecker || null;
  63.  
  64. if (this.answerChecker) {
  65. clearInterval(intervalId);
  66.  
  67. if (this.answerChecker.oldEvaluate) return;
  68. const answerChecker = this.answerChecker;
  69.  
  70. console.log('Found new answerChecker');
  71.  
  72. const oldEvaluate = answerChecker.evaluate.bind(answerChecker);
  73. answerChecker.oldEvaluate = oldEvaluate;
  74.  
  75. /** @type {(fns: TryEvaluationFunction[]) => EvaluationFunction} */
  76. const evaluateWith = (fns) => {
  77. return (e) => {
  78. for (const fn of fns) {
  79. const r = fn(
  80. e,
  81. evaluateWith(fns.filter((it) => it !== fn)),
  82. );
  83. if (r) return r;
  84. }
  85. return oldEvaluate(e);
  86. };
  87. };
  88.  
  89. answerChecker.evaluate = evaluateWith(this.mods);
  90. }
  91.  
  92. if (startDate + 5000 < +new Date()) {
  93. clearInterval(intervalId);
  94. }
  95. }, 500);
  96. }
  97. });
  98. }
  99. }
  100.  
  101. window.modAnswerChecker = window.modAnswerChecker || new ModAnswerChecker();
  102. })();

QingJ © 2025

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