WaniKani Item Annotator

Annotates radical, kanji and vocab pages with SRS colours. Original script by jeshuamorrissey.

当前为 2017-04-05 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name WaniKani Item Annotator
  3. // @namespace mempo
  4. // @description Annotates radical, kanji and vocab pages with SRS colours. Original script by jeshuamorrissey.
  5. // @author Mempo
  6. // @version 1.3.1
  7. // @include http://www.wanikani.com/radical*
  8. // @include http://www.wanikani.com/kanji*
  9. // @include http://www.wanikani.com/vocabulary*
  10. // @include http://www.wanikani.com/account*
  11. // @include https://www.wanikani.com/radical*
  12. // @include https://www.wanikani.com/kanji*
  13. // @include https://www.wanikani.com/vocabulary*
  14. // @include https://www.wanikani.com/account*
  15. // @grant none
  16. // ==/UserScript==
  17.  
  18.  
  19. console.log('@@@@ start of WaniKani Item Annotator');
  20.  
  21. var apiKey = $.jStorage.get('apiKey');
  22.  
  23. if(apiKey === null){ //not initialized yet
  24. console.log('#### no apiKey found');
  25. if (window.location.href.indexOf('account') != - 1) {
  26. apiKey = "" + retrieveAPIkey();
  27. console.log('@@@@@' + apiKey);
  28. $.jStorage.set('WIA_apiKey', apiKey);
  29. } else {
  30. var okcancel = confirm('WaniKani Item Annotator has no API key entered!\nPress OK to go to your settings page and retrieve your API key!');
  31. if (okcancel == true) {
  32. window.location = 'https://www.wanikani.com/settings/account';
  33. return;
  34. }
  35. }
  36. }
  37.  
  38. console.log('#### apiKey is: ' + apiKey);
  39. // Determine which API call we are going to make.
  40. var target = 'kanji';
  41. if (window.location.href.indexOf('vocabulary') >= 0) {
  42. target = 'vocabulary';
  43. } else if (window.location.href.indexOf('radicals') >= 0) {
  44. target = 'radicals';
  45. }
  46.  
  47. console.log('@@@ target is: ' + target);
  48. var css =
  49. '.WIA_apprentice {' +
  50. ' background: #f100a0 linear-gradient(to bottom,#f0a,#dd0093) !important;' +
  51. ' border-color: #f100a0 !important;' +
  52. '} ' +
  53. '.WIA_guru {' +
  54. ' background: #882d9e linear-gradient(to bottom,#aa38c6,#882d9e) !important;' +
  55. ' border-color: #882d9e !important;' +
  56. '} ' +
  57. '.WIA_master {' +
  58. ' background: #294ddb linear-gradient(to bottom,#5571e2,#294ddb) !important;' +
  59. ' border-color: #294ddb !important;' +
  60. '} ' +
  61. '.WIA_enlighten {' +
  62. ' background: #0093dd linear-gradient(to bottom,#0af,#0093dd) !important;' +
  63. ' border-color: #0093dd !important;' +
  64. '} ' ;
  65.  
  66.  
  67. // ADD CSS
  68. addStyle(css);
  69.  
  70. // Load the API data.
  71.  
  72. $.get(apiURL(target), function(xhr) {
  73. // Parse the response.
  74. //console.log("###### JSON RESPONSE");
  75. //console.log(xhr);
  76.  
  77. // Build up an item mapping from Kanji --> Information
  78. var itemMapping = {};
  79.  
  80. // Get the actual request information. If the target is vocabulary, for some reason
  81. // we have to got an additional level into 'request_information.general'. This is
  82. // probably to account for specialised vocab which will be added later.
  83. var information = xhr.requested_information;
  84. if (target === 'vocabulary') {
  85. information = information.general;
  86. }
  87.  
  88. for (var i in information) {
  89. var item = information[i];
  90.  
  91. // Extract the character (Kanji) from the item.
  92. var character = item.character;
  93.  
  94. // If we are looking at radicals, use the meaning instead (convert the meaning to
  95. // the 'user friendly' format).
  96. if (target === 'radicals') {
  97. character = item.meaning.toLowerCase();
  98. }
  99.  
  100. // Get the SRS level from the item. The 'user_specific' object will be `null` if the item
  101. // hasn't been unlocked yet. In this case, just set the SRS level to `null`.
  102. var srs = null;
  103. if (item.user_specific) {
  104. srs = item.user_specific.srs;
  105. }
  106.  
  107. // Build the mapping for this character.
  108. itemMapping[character] = {
  109. 'srs': srs
  110. };
  111. }
  112. //console.log('&&&&& ITEM MAPPING');
  113. // console.log(itemMapping);
  114.  
  115. // Actually do stuff with this mapping.
  116. main(itemMapping, target);
  117. });
  118.  
  119. /**
  120. * Mapping of SRS --> Object, where the object contains a series
  121. * of transformation colors. These transformations will be applied
  122. * via the element.style property, so should have priority.
  123. */
  124.  
  125.  
  126.  
  127. /**
  128. * Main function: actually annotate the elements. Takes as input information from
  129. * the WK API as a mapping from Japanese Element --> Object. In this case, the
  130. * object need only contain the SRS level of the element.
  131. */
  132. function main(itemMapping, target) {
  133. // Find all characters on the page.
  134. var elements = $('.character-item');
  135. //console.log('size of elements is ' + elements.size());
  136. var i= 0;
  137. for (i=0;i<elements.size();i++) {
  138. var element = elements[i];
  139. //console.log(element);
  140. /*
  141. // If this isn't actually an element (could happen, who knows), just skip it.
  142. if (!element.querySelector || !element.style) {
  143. console.log('///////////////////////////// What the shit why are we here.');
  144. continue;
  145. }
  146. */
  147.  
  148.  
  149. // The japanese value to look up in the item mapping is the text of this element.
  150. var japanese = element.querySelector('.character').textContent;
  151.  
  152. // If we happen to be looking at radicals, some of them use pictures instead. It is
  153. // simpler to use the radical meaning in this case (as there is only one meaning).
  154. // The meaning is stored in the last list element within the element (for some reason
  155. // there is a &nbsp; list element first).
  156. if (target === 'radicals') {
  157. var radicalLink = element.querySelector('a').getAttribute('href');
  158. japanese = radicalLink.slice(radicalLink.lastIndexOf('/') + 1);
  159. //console.log('@@@@@ ' + japanese);
  160. }
  161.  
  162.  
  163.  
  164. // If we couldn't find the SRS information for the element, or the element hasn't been unlocked
  165. // yet, just ignore it.
  166. /*
  167. if (!japanese.srs) {
  168. console.log('///////////// What are you doing here????');
  169. continue;
  170. }
  171. */
  172. console.log(japanese.srs);
  173.  
  174. // Find the corresponding colors.
  175. //var colors = colorDict[japanese.srs];
  176. $(element).addClass("WIA_" + itemMapping[japanese].srs);
  177. }
  178. }
  179. function retrieveAPIkey() {
  180. var apiKey = document.getElementById('user_api_key').value;
  181. alert('API key was set to: ' + apiKey);
  182. if (apiKey) {
  183. return apiKey;
  184. }
  185. }
  186.  
  187. function apiURL(target){
  188. return 'https://www.wanikani.com/api/user/' + apiKey + '/' + target;
  189. }
  190.  
  191. function addStyle(aCss) {
  192. var head, style;
  193. head = document.getElementsByTagName('head')[0];
  194. if (head) {
  195. style = document.createElement('style');
  196. style.setAttribute('type', 'text/css');
  197. style.textContent = aCss;
  198. head.appendChild(style);
  199. return style;
  200. }
  201. return null;
  202. }
  203.