// ==UserScript== // @name Wanikani Burn Reviews // @namespace wkburnreview // @description Adds a space on the main page that reviews random burned items // @exclude *.wanikani.com // @include *.wanikani.com/dashboard* // @version 0.9.7.2 // @author Samuel H // IMPORTANT: ADD @ BEFORE require BELOW OR THE SCRIPT WILL NOT WORK // require https://raw.github.com/WaniKani/WanaKana/master/lib/wanakana.min.js // @grant none /* This script is licensed under the Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0) license * Details: http://creativecommons.org/licenses/by-nc/4.0/ */ //IMPORTANT: YOU MUST PASTE YOUR API KEY BELOW INSIDE THE QUOTES FOR THIS SCRIPT TO WORK PROPERLY apiKey = "ENTER API KEY HERE"; //"API KEY HERE" //CHANGE THIS TO true IF YOU WANT TO LOAD PREVIOUS DATA AND SKIP LOADING: IF YOU DO THIS YOU MUST RUN THE SCRIPT WITH useCache = false FOR IT TO UPDATE YOUR BURNED ITEMS useCache = false; //true; function getSection() { var strSection = '
\
\

Burn Reviews

\
\ \
\
'; return strSection; } function getFadeCSS() { var strFadeIn = ''; return strFadeIn; } function getButtonCSS() { var strButtons = ''; return strButtons; } function rand(low, high) { return Math.floor(Math.random()*(high+1)) + low; } function filterRadicalData(data) { var dataArr = {}; for (var d = 1; d < data.length; d++) { if (data[d].indexOf('"burned":true') > -1) { dataArr[Object.keys(dataArr).length] = {"character": data[d].substring(0, 1), "meaning": data[d].substring(data[d].indexOf('"meaning":"') + 11, data[d].indexOf('","image"')).split(", "), "image": data[d].substring(data[d].indexOf('"image":"') + 10, data[d].indexOf('","level"')).split(", ")}; } } return dataArr; } function filterKanjiData(data) { var dataArr = {}; for (var d = 1; d < data.length; d++) { if (data[d].indexOf('"burned":true') > -1) { dataArr[Object.keys(dataArr).length] = {"character": data[d].substring(0, 1), "meaning": data[d].substring(data[d].indexOf('"meaning":"') + 11, data[d].indexOf('","onyomi"')).split(", "), "onyomi": data[d].substring(data[d].indexOf('"onyomi":"') + 10, data[d].indexOf('","kunyomi"')).split(", "), "kunyomi": data[d].substring(data[d].indexOf('"kunyomi":"') + 11, data[d].indexOf('","important')).split(", "), "important_reading": data[d].substring(data[d].indexOf('"important_reading":"') + 21, data[d].indexOf('","level"'))}; } } return dataArr; } function filterVocabData(data) { var dataArr = {}; for (var l = 0; l < Object.keys(data).length; l++) { for (var d = 1; d < Object.keys(data[l]).length; d++) { if (data[l][d].indexOf('"burned":true') > -1) { dataArr[Object.keys(dataArr).length] = {"character": data[l][d].substring(0, data[l][d].indexOf('"')), "kana": data[l][d].substring(data[l][d].indexOf('"kana":"') + 8, data[l][d].indexOf('","meaning"')).split(", "), "meaning": (data[l][d].substring(data[l][d].indexOf('"meaning":"') + 11, data[l][d].indexOf('","level"'))).split(", ")}; } } } return dataArr; } function getBurnReview(firstReview) { curBRAnswered = false; $("#user-response").attr("disabled", false).val("").focus(); if (!firstReview) { $(".answer-exception-form").css("display", "none"); if ((curBRItemType == 0 && curBRProgress > 0) || curBRProgress == 2) { newBRItem(); updateBRItem(true); } if (curBRItemType > 0 && (curBRProgress < 1 || $("#answer-form fieldset").hasClass("correct"))) { if (curBRType == 0) { curBRType = 1; wanakana.bind(document.getElementById('user-response')); $("#user-response").attr({lang:"ja",placeholder:"答え"}); $("#question-type").removeClass("meaning").addClass("reading"); } else { curBRType = 0; wanakana.unbind(document.getElementById('user-response')); $("#user-response").removeAttr("lang").attr("placeholder","Your Response"); $("#question-type").removeClass("reading").addClass("meaning"); } } else if (curBRItemType == 0) { wanakana.unbind(document.getElementById('user-response')); $("#user-response").removeAttr("lang").attr("placeholder","Your Response"); $("#question-type").removeClass("reading").addClass("meaning"); } document.getElementById("question-type-text").innerHTML = (curBRType == 0) ? "Meaning" : ((curBRItemType == 1) ? ((kanjiData[curBRItem]["important_reading"] == "onyomi") ? "Onyomi Reading" : "Kunyomi Reading") : "Reading"); document.getElementById('user-response').value = ""; $("#answer-form fieldset").removeClass("correct").removeClass("incorrect"); } else { document.getElementById("new-item").onclick = skipItem; $("body").prepend('
'); newBRItem(); var characterText = (curBRItemType == 0) ? radicalData[curBRItem]["character"] : ((curBRItemType == 1) ? kanjiData[curBRItem]["character"] : vocabData[curBRItem]["character"]); var reviewTypeText = ((curBRType < 1) ? "Meaning" : (curBRItemType == 0) ? radicalData[curBRItem]["character"] : ((curBRItemType == 1) ?kanjiData[curBRItem]["important_reading"].substring(0, 1).toUpperCase() + kanjiData[curBRItem]["important_reading"].substring(1) + " Reading" : "Reading")); strReview = '\
\
\
部首
\
漢字
\
単語
\
\
' + characterText + '
\

' + reviewTypeText + '

\
\ \ \
\
\ '; return strReview; } } function newBRItem() { if (radicalsEnabled) { if (kanjiEnabled) { if (vocabularyEnabled) { curBRItem = rand(1, Object.keys(radicalData).length + Object.keys(kanjiData).length + Object.keys(vocabData).length - 1); curBRItemType = (curBRItem < Object.keys(radicalData).length) ? 0 : ((curBRItem < Object.keys(radicalData).length + Object.keys(kanjiData).length) ? 1 : 2); } else { curBRItem = rand(1, Object.keys(radicalData).length + Object.keys(kanjiData).length - 1); curBRItemType = (curBRItem < Object.keys(radicalData).length) ? 0 : 1; } } else { if (vocabularyEnabled) { curBRItem = rand(1, Object.keys(radicalData).length + Object.keys(vocabData).length - 1); curBRItemType = (curBRItem < Object.keys(radicalData).length) ? 0 : 2; } else { curBRItem = rand(1, Object.keys(radicalData).length - 1); curBRItemType = 0; } } } else if (kanjiEnabled) { if (vocabularyEnabled) { curBRItem = rand(1, Object.keys(kanjiData).length + Object.keys(vocabData).length - 1); curBRItemType = (curBRItem < Object.keys(radicalData).length) ? 0 : 1; } else { curBRItem = rand(1, Object.keys(kanjiData).length - 1); curBRItemType = 1; } } else { curBRItem = rand(1, Object.keys(vocabData).length - 1); curBRItemType = 2; } if (curBRItemType == 0) curBRType = 0; else { curBRType = rand(0, 1); if (curBRItemType == 1) { if (radicalsEnabled) curBRItem -= Object.keys(radicalData).length; } else if (curBRItemType == 2) { if (radicalsEnabled) { if (kanjiEnabled) curBRItem -= (Object.keys(radicalData).length + Object.keys(kanjiData).length); else curBRItem -= (Object.keys(radicalData).length); } else if (kanjiEnabled) curBRItem -= Object.keys(kanjiData).length; } } curBRProgress = 0; } function updateBRItem(updateText) { if (updateText) $(".bri").html(((curBRItemType == 0) ? radicalData[curBRItem]["character"] : (curBRItemType == 1) ? kanjiData[curBRItem]["character"] : vocabData[curBRItem]["character"])); var bg = (curBRItemType == 0) ? "#00a0f1" : ((curBRItemType == 1) ? "#f100a0" : "#a000f1"); var bgi = "linear-gradient(to bottom, "; bgi += (curBRItemType == 0) ? "#0af, #0093dd" : ((curBRItemType == 1) ? "#f0a, #dd0093" : "#a0f, #9300dd"); $(".brk").css({"background-color": bg, "background-image": bgi, "background-repeat": "repeat-x", "height": "39px", "padding-top": "28px", "padding-bottom": "3px", "margin-top": "0px", "margin-left": "0px", "text-align": "center"}); } function skipItem() { curBRProgress = 2; getBurnReview(false); return false; } function getRadicalData() { $("#loading").html('

Retrieving radical data...

'); var req = new XMLHttpRequest(); req.open('GET', 'https://www.wanikani.com/api/user/' + apiKey + '/radicals', true); req.onreadystatechange = function() { if (req.readyState === 4) { if (req.status >= 200 && req.status < 400) { radicalData = filterRadicalData(req.responseText.split('"character":"')); localStorage.setItem("burnedRadicals", JSON.stringify(radicalData)); getKanjiData(); } else { alert("error"); } } }; req.send(); } function getKanjiData() { $("#loading").html('

Retrieving kanji data...

'); var req = new XMLHttpRequest(); req.open('GET', 'https://www.wanikani.com/api/user/' + apiKey + '/kanji', true); req.onreadystatechange = function() { if (req.readyState === 4) { if (req.status >= 200 && req.status < 400) { kanjiData = filterKanjiData(req.responseText.split('"character":"')); localStorage.setItem("burnedKanji", JSON.stringify(kanjiData)); getVocabData(1); } else { alert("error"); } } }; req.send(); } function getVocabData(lv) { $("#loading").html('

Retrieving vocabulary data...

'); var req = new XMLHttpRequest(); req.open('GET', 'https://www.wanikani.com/api/user/' + apiKey + '/vocabulary/' + lv, true); req.onreadystatechange = function() { if (req.readyState === 4) { if (req.status >= 200 && req.status < 400) { vocabData[lv - 1] = req.responseText.split('"character":"'); if (lv == parseInt($(".dropdown-toggle span").html())) { vocabData = filterVocabData(vocabData); localStorage.setItem("burnedVocab", JSON.stringify(vocabData)); initBurnReviews(); } else { getVocabData(lv + 1); } } else { alert("error"); } } }; req.send(); } function getWKData() { /*localStorage.removeItem("radicalsEnabled"); localStorage.removeItem("kanjiEnabled"); localStorage.removeItem("vocabularyEnabled");*/ if (localStorage.getItem("radicalsEnabled") !== null) radicalsEnabled = false; if (localStorage.getItem("kanjiEnabled") !== null) kanjiEnabled = false; if (localStorage.getItem("vocabularyEnabled") !== null) vocabularyEnabled = false; if (localStorage.getItem("burnedRadicals") == null) getRadicalData(); else if (localStorage.getItem("burnedKanji") == null) getKanjiData(); else if (localStorage.getItem("burnedVocab") == null) getVocabData(1); else { radicalData = JSON.parse(localStorage.getItem("burnedRadicals")); kanjiData = JSON.parse(localStorage.getItem("burnedKanji")); vocabData = JSON.parse(localStorage.getItem("burnedVocab")); initBurnReviews(); } } function clearBurnedItemData() { localStorage.removeItem("burnedRadicals"); localStorage.removeItem("burnedKanji"); localStorage.removeItem("burnedVocab"); } function confirmRes() { $(".answer-exception-form").css({"display": "block", "opacity": "0", "-webkit-transform": "translateY(20px)"}).removeClass("animated fadeInUp"); $(".answer-exception-form span").html(""); $(".answer-exception-form").addClass("animated fadeInUp") $(".answer-exception-form span").html('Are you sure you want to Resurrect the ' + ((curBRItemType == 1) ? 'kanji item "' + kanjiData[curBRItem]["character"] : 'vocabulary item "' + vocabData[curBRItem]["character"]) + '"?'); document.getElementById("answer-exception").onclick = "return false"; return false; } function initBurnReviews() { $("#loading").remove(); $("head").append(''); $(getFadeCSS()).appendTo($("head")); $(getButtonCSS()).appendTo($("head")); $("ul").css("padding-left", "0px"); $(getBurnReview(true)).insertAfter($(".burn-reviews.kotoba-table-list.dashboard-sub-section h3")); updateBRItem(false); if (curBRType == 0) { wanakana.unbind(document.getElementById('user-response')); $("#user-response").removeAttr("lang").attr("placeholder","Your Response"); $("#question-type").addClass("meaning"); } else { wanakana.bind(document.getElementById('user-response')); $("#user-response").attr({lang:"ja",placeholder:"答え"}); $("#question-type").addClass("reading"); } $(".brb div").css({"background-repeat": "repeat-x", "color": "#fff", "padding": "3px 5px 0px 5px", "width": "20px", "height": "32px", "vertical-align": "middle", "font-size": "14px"}).mouseover(function() { $(this).css("text-shadow", "0 0 0.2em #fff"); }).mouseout(function() { $(this).css("text-shadow", ""); }).click(function() { var cancel = false; if ($(this).hasClass("on")) { if ((radicalsEnabled && kanjiEnabled) || (radicalsEnabled && vocabularyEnabled) || (kanjiEnabled && vocabularyEnabled)) { if ($(this).attr("class") == "brbr on") { localStorage.setItem("radicalsEnabled", false); radicalsEnabled = false; if (curBRItemType == 0) skipItem(); } else if ($(this).attr("class") == "brbk on") { localStorage.setItem("kanjiEnabled", false); kanjiEnabled = false; if (curBRItemType == 1) skipItem(); } else if ($(this).attr("class") == "brbv on") { localStorage.setItem("vocabularyEnabled", false); vocabularyEnabled = false; if (curBRItemType == 2) skipItem(); } } else cancel = true; } else { if ($(this).attr("class") == "brbr") { localStorage.removeItem("radicalsEnabled"); radicalsEnabled = true; } else if ($(this).attr("class") == "brbk") { localStorage.removeItem("kanjiEnabled"); kanjiEnabled = true; } else if ($(this).attr("class") == "brbv") { localStorage.removeItem("vocabularyEnabled"); vocabularyEnabled = true; } } if (!cancel) $(this).toggleClass("on"); }); $(".brb div span").css({"-ms-writing-mode": "tb-rl", "-webkit-writing-mode": "vertical-rl", "-moz-writing-mode": "vertical-rl", "-ms-writing-mode": "vertical-rl", "writing-mode": "vertical-rl", "-webkit-touch-callout": "none", "-webkit-user-select": "none", "-khtml-user-select": "none", "-moz-user-select": "none", "-ms-user-select": "none", "user-select": "none", "cursor":"default"}); $(".bri").css({"color": "#ffffff", "font-size": "48px", "text-shadow": "0 1px 0 rgba(0,0,0,0.2)"}); $(".brk").click(function () { if ($("#dim-overlay").css("display") == "none") { $(".burn-reviews.kotoba-table-list.dashboard-sub-section").css({"-webkit-transition": "1s ease-in-out", "-moz-transition": "1s ease-in-out", "-o-transition": "1s ease-in-out", "transition": "1s ease-in-out"}).css("transform", "scaleX(2)scaleY(2)").one('transitionend webkitTransitionEnd', function() { $("#dim-overlay").removeClass("fadeIn"); if (queueBRAnim) { queueBRAnim = false; allowQueueBRAnim = false; $("#dim-overlay").trigger("click"); } else allowQueueBRAnim = true; }); $("#dim-overlay").css("display", "block").addClass("fadeIn"); } else if (!queueBRAnim && allowQueueBRAnim) queueBRAnim = true; }); $("#dim-overlay").click(function () { if (!$(this).hasClass("fadeIn")) { $(this).addClass("fadeOut"); $(".burn-reviews.kotoba-table-list.dashboard-sub-section").one('transitionend webkitTransitionEnd', function() { $("#dim-overlay").removeClass("fadeOut").css("display", "none"); if (queueBRAnim) { queueBRAnim = false; allowQueueBRAnim = false; $(".brk").trigger("click"); } else allowQueueBRAnim = true; }); $(".burn-reviews.kotoba-table-list.dashboard-sub-section").css("transform", "scaleX(1)scaleY(1)"); } else if (!queueBRAnim && allowQueueBRAnim) queueBRAnim = true; }); $(".answer-exception-form span").css({"background-color": "rgba(162, 162, 162, 0.75)", "box-shadow": "3px 3px 0 rgba(225, 225, 225, 0.75)"}); } function checkBurnReviewAnswer() { var response = $("#user-response").val().toLowerCase(); var match = false; var answers; $("#user-response").attr("disabled", true); if (curBRType == 0) answers = (curBRItemType == 0) ? radicalData[curBRItem]["meaning"] : ((curBRItemType == 1) ? kanjiData[curBRItem]["meaning"] : vocabData[curBRItem]["meaning"]); else answers = (curBRItemType == 1) ? kanjiData[curBRItem][kanjiData[curBRItem]["important_reading"]] : vocabData[curBRItem]["kana"]; if (answers instanceof Array) { for (var a = 0; a < Object.keys(answers).length; a++) { if (response == answers[a]) match = true; } } else if (response == answers) match = true; if ((curBRType == 0 && isAsciiPresent(response)) || (!isAsciiPresent(response) && curBRType == 1 && response !== "")) { //alert(evaluate(((curBRType == 0) ? "meaning" : "reading"),$("#user-response").val()).join(",")); if (match) { $("#answer-form fieldset").removeClass("incorrect"); $("#answer-form fieldset").addClass("correct"); curBRProgress++; } else { $("#answer-form fieldset").removeClass("correct"); $("#answer-form fieldset").addClass("incorrect"); $(".answer-exception-form span").html('The answer was:
"' + ((answers instanceof Array) ? answers.join(", ") : answers) + '"
Resurrect this item?'); $(".answer-exception-form").css({"display": "block"}).addClass("animated fadeInUp"); document.getElementById("answer-exception").getElementsByTagName("span")[0].getElementsByTagName("a")[0].onclick = confirmRes; } curBRAnswered = true; } else { //$("#answer-form").effect( "shake", {}, 100 ); $("#user-response").attr("disabled", false); } } function evaluate(e,t){ var n,r,i,s,o,u,a,f,l,c,h; i=[]; u=[]; s=((curBRItemType == 1) ? kanjiData[curBRItem]["character"] : vocabData[curBRItem]["character"]); n=!1; l=!1; f=!1; o=!1; t=$.trim(t); e==="reading"&&(t=t.replace("n","ん")); $("#user-response").val(t); if(e==="reading"){ s.kan?(s.emph==="onyomi"?(i=s.on,u=s.kun):(i=s.kun,u=s.on),o=checkIfOtherKanjiReading(t,u,i)):s.voc&&(i=s.kana),i.length>1&&(f=!0); for(a in i) r=i[a]; t===r&&(l=!0,n=!0); } else { i=$.merge(s.en,s.syn); i.length>1&&(f=!0); t=stringFormat(t); for(a in i) r=i[a]; r=stringFormat(r); h=levenshteinDistance(r,t); c=distanceTolerance(r); h<=c&&(l=!0); h===0&&(n=!0) } return {passed:l,accurate:n,multipleAnswers:f,exception:o}; } function checkIfOtherKanjiReading(e,t,n){ var r,i,s; s=!1; for(i in t)r=t[i]; e===r.replace(/\..*/,"")&&(s=!0) for(i in n) r=n[i]; e===r&&(s=!1); return s; } function isAsciiPresent(e){ return (curBRType == 0) ? !/[^a-z]/i.test(e) : /[^ぁ-ー]/.test(e); //e=e[e.length-1]==="n"?e.slice(0,-1):e; } function stringFormat(e){ return e=e.toLowerCase().replace("-"," ").replace(".","").replace("'",""); e.substr(-1)==="s"&&(e=e.slice(0,-1)),e; } function distanceTolerance(e){ switch(e.length){ case 1:case 2:case 3:return 0; case 4:case 5:return 1; case 6:case 7:return 2; default:return 2+Math.floor(e.length/7)*1; } } document.addEventListener('keydown', function(event) { if(event.keyCode == 13) { //Enter if (!curBRAnswered) checkBurnReviewAnswer(); else getBurnReview(false); } }); curBRItem = -1; curBRType = -1; curBRItemType = -1; curBRProgress = 0; curBRAnswered = false; queueBRAnim = false; allowQueueBRAnim = true; radicalsEnabled = true; kanjiEnabled = true; vocabularyEnabled = true; radicalData = ""; kanjiData = ""; vocabData = {}; $(".low-percentage.kotoba-table-list.dashboard-sub-section").parent().wrap('
'); $(getSection()).insertAfter($(".low-percentage.kotoba-table-list.dashboard-sub-section").parent()); if (!useCache) clearBurnedItemData(); getWKData(); // @downloadURL none // ==/UserScript==