[Userscript] auto-commit; the end of the enter key

I think it’s possibly a little broken again

1 Like

Try this:

// ==UserScript==
// @name         WK Auto Commit (09.01.25)
// @namespace    WKAUTOCOMMIT
// @version      0.4.8-fixed-fast-2
// @description  Auto submits on exact accepted answer match (incl. user synonyms) and advances ASAP.
// @author       Johannes Mikulasch (original) + patch
// @match        https://www.wanikani.com/subjects/*
// @match        https://www.wanikani.com/subject-lessons/*
// @match        https://www.wanikani.com/review/*
// @match        https://www.wanikani.com/lesson/*
// @match        https://www.wanikani.com/lessons/*
// @match        https://www.wanikani.com/reviews/*
// @match        https://www.wanikani.com/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

'use strict';

let activated = true, expected = [], synonyms = {}, bound = false, nextTimer = null;
const q = (s) => document.querySelector(s);
const input = () => q('#user-response');
const btn = () => q('.quiz-input__submit-button');
const lightning = () => !!q('.doublecheck-active');
const s = (v) => (v == null ? '' : String(v).replace(/\s/g, '').toLowerCase());

const toggle = () => {
  const b = q('#WKAUTOCOMMIT_button'); if (!b) return;
  activated = !activated;
  b.style.opacity = activated ? 1 : 0.5;
  b.textContent = activated ? 'Auto Commit is on' : 'Auto Commit is off';
  b.title = activated ? 'Switch auto commit off' : 'Switch auto commit on';
};

const addBtn = () => {
  if (q('#WKAUTOCOMMIT_button')) return;
  const f = q('.quiz-footer'); if (!f) return;
  const d = document.createElement('div');
  d.id = 'WKAUTOCOMMIT_button';
  d.textContent = 'Auto Commit is on';
  d.title = 'Toggle Auto Commit Mode';
  d.onclick = toggle;
  Object.assign(d.style, {
    backgroundColor: '#C55', opacity: 1, display: 'inline-block', fontSize: '0.8125em',
    color: '#FFF', cursor: 'pointer', padding: '10px', marginLeft: '10px', verticalAlign: 'bottom'
  });
  f.appendChild(d);
};

const loadSyn = () => {
  if (loadSyn.loaded) return;
  const t = q('script[data-quiz-user-synonyms-target]'); if (!t) return;
  try { synonyms = JSON.parse(t.innerHTML); loadSyn.loaded = true; } catch {}
};

window.addEventListener('didUpdateUserSynonyms', (e) => {
  if (e?.detail) synonyms[e.detail.subjectId] = e.detail.synonyms;
});

const isAdvanceReady = (b) => {
  if (!b) return false;
  if (b.disabled || b.getAttribute('aria-disabled') === 'true') return false;
  const t = (b.textContent || '').trim().toLowerCase();
  if (t.includes('next') || t.includes('continue')) return true;
  if (t && (t.includes('submit') || t.includes('answer') || t.includes('check'))) return false;
  return true;
};

const clickNextASAP = () => {
  if (nextTimer) return;
  const start = performance.now(), maxWait = 700, interval = 10;
  nextTimer = setInterval(() => {
    const b = btn(); if (!b) return;
    if (isAdvanceReady(b) || performance.now() - start > maxWait) {
      clearInterval(nextTimer); nextTimer = null; b.click();
    }
  }, interval);
};

const commit = () => {
  if (!commit.usable) return;
  const b = btn(); if (!b) return;
  commit.usable = false;
  b.click();
  if (!lightning()) clickNextASAP();
};

const check = () => {
  const i = input(); if (!i) return;
  const cur = s(i.value);
  for (let k = 0; k < expected.length; k++) if (cur === s(expected[k])) { commit(); break; }
};

const bind = () => {
  const i = input(); if (!i || bound) return;
  i.addEventListener('keyup', () => { if (activated) check(); }, { capture: true });
  bound = true;
};

window.addEventListener('willShowNextQuestion', (e) => {
  bound = false;
  if (nextTimer) { clearInterval(nextTimer); nextTimer = null; }
  bind(); addBtn(); loadSyn();
  expected = [];
  const item = e?.detail, subj = item?.subject;
  if (!subj) { commit.usable = true; return; }
  const ok = ['alternative', 'primary', 'allowed'];
  if (item.questionType === 'meaning') {
    if (Array.isArray(subj.meanings)) expected = expected.concat(subj.meanings.filter(x => x && ok.includes(x.kind)).map(x => x.text));
    const syn = (subj.id in synonyms) ? synonyms[subj.id] : [];
    if (Array.isArray(syn)) expected = expected.concat(syn);
  } else if (item.questionType === 'reading') {
    if (Array.isArray(subj.readings)) expected = expected.concat(
      subj.readings
        .filter(x => x && ok.includes(x.kind) && (String(subj.type).toLowerCase() !== 'kanji' || subj.primary_reading_type === x.type))
        .map(x => x.text)
    );
  }
  commit.usable = true;
});

(() => console.log('WK Auto Commit: Initialized'))();

1 Like