Satori Reader WaniKani Lookup

Lookup Kanji and Vocab you have learned in WaniKani on Satori Reader.

// ==UserScript==
// @name        Satori Reader WaniKani Lookup
// @namespace   stefanbeyer
// @description Lookup Kanji and Vocab you have learned in WaniKani on Satori Reader.
// @include     https://satorireader.com/articles/*
// @include     https://www.satorireader.com/articles/*
// @author      Stefan Beyer
// @version     3
// @copyright   2017 Stefan Beyer, WaniKani and Satori Reader logos and trademarks copyright of their respective owners
// @license     MIT; http://opensource.org/licenses/MIT
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_registerMenuCommand
// @grant       GM_xmlhttpRequest
// @require     http://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js
// ==/UserScript==
$(document).ready(function () {
  var api_key_key = 'SR_WK_API_KEY';
  var api_key = GM_getValue(api_key_key);
  var levels = '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60';
  var kanji_url = 'https://www.wanikani.com/api/user/' + api_key + '/kanji/' + levels;
  var vocab_url = 'https://www.wanikani.com/api/user/' + api_key + '/vocabulary/' + levels;
  var icon_url = 'https://cdn.wanikani.com/assets/favicon-cc5fd9e4485a2b407d0bc283f8f913cf6a3dd00172895dc845f0f4bd90ffdc41.ico';
  var kanji_link = 'https://www.wanikani.com/kanji/';
  var vocab_link = 'https://www.wanikani.com/vocabulary/';
  var other_kanji_link = 'http://tangorin.com/kanji/';
  var kanji = [0x4e00 ,0x9faf];
  var kanji_rare = [0x3400, 0x4dbf];
  var kanji_list;
  var vocab_list;
  function lookupWords() {
    // Create WK links
    $('.tooltip .word.kanji-knowledge-na .wpt').each(function (index) {
      var word = $(this);
      var replace = {
      };
      kanji_list.forEach(function (element) {
        var kanji = element.character;
        var learned = element.user_specific !== null;
        if (word.text().includes(kanji)) {
          var css = learned ? 'color:black' : 'color:#aaa';
          replace[kanji] = '<a style="' + css + '" target="_blank" href="' + kanji_link + kanji + '"\'>' + kanji + '</a>';
        }
      });
      var text = word.text();
      var html = '';
      for (var i = 0, len = text.length; i < len; i++) {
        var char = text[i];
        var charCode = text.charCodeAt(i);
        if (char in replace) {
          html += replace[char];
        } else {
          if ((charCode >= kanji[0] && charCode <= kanji[1]) || (charCode >= kanji_rare[0] && charCode <= kanji_rare[1])) {
            html += '<a style="color:#ff8383" target="_blank" href="' + other_kanji_link + char + '"\'>' + char + '</a>';
          } else {
            html += char;
          }
        }
      }
      word.html(html);
    });
    // check if in WK vocab
    $('.note-body:not(.wk) .tooltip-button:not(.wk-button)').each(function (index) {
      var note = $(this).parent();
      note.addClass('wk');
      var character = '';
      note.find('.expression .wpt').each(function (index) {
        character += $(this).text();
      });
      var available = false;
      var level;
      var learned;
      vocab_list.forEach(function (element) {
        var wchar = element.character;
        if (wchar == character) {
          available = true;
          learned = element.user_specific !== null;
          level = element.level;
        }
      });
      if (available) {
        var text;
        if (learned) {
          text = 'Added on Level ' + level;
        } else {
          text = 'Level ' + level;
        }
        var button = note.add('<span class="tooltip-button tooltip-button-active wk-button" style="background-color: #ff00aa; border-color: #b6007a"><span class="tooltip-icon" style="background-image: url(' + icon_url + '); height: 16px; width: 16px; margin: 2px 0 0 0;" ></span><span class="text">' + text + '</span></span>');
        button.last().click(function () {
          window.open(vocab_link + character, '_blank');
        });
        button.appendTo(note);
      }
    });
  }
  if (api_key !== null && api_key !== '') {
    GM_xmlhttpRequest({
      method: 'GET',
      url: kanji_url,
      onload: function (response) {
        kanji_list = JSON.parse(response.responseText).requested_information;
        lookupWords();
      }
    });
    GM_xmlhttpRequest({
      method: 'GET',
      url: vocab_url,
      onload: function (response) {
        vocab_list = JSON.parse(response.responseText).requested_information;
        lookupWords();
      }
    });
    $('.word').each(function (index) {
      var word = $(this);
      var observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
          if (word.hasClass('word-selected')) {
            lookupWords();
          }
        });
      });
      var config = { attributes: true, childList: false, characterData: false };
      observer.observe(this, config);
    });
  }
  GM_registerMenuCommand('Satori Reader WaniKani Lookup -> Set API Key', function () {
    var key = GM_getValue(api_key_key);
    var val = prompt('Edit the API key', key);
    if (val !== null) {
      GM_setValue(api_key_key, String(val));
    }
  });
});