Greasy Fork is available in English.

Show Total Lesson Count - WaniKani

Changes the count of lessons on the Today's Lessons tile to show the total number of available lessons in addition to the number selected for you

Από την 04/08/2024. Δείτε την τελευταία έκδοση.

  1. // ==UserScript==
  2. // @name Show Total Lesson Count - WaniKani
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.4.6
  5. // @description Changes the count of lessons on the Today's Lessons tile to show the total number of available lessons in addition to the number selected for you
  6. // @license MIT
  7. // @author LupoMikti
  8. // @match https://www.wanikani.com/*
  9. // @grant none
  10. // @supportURL https://community.wanikani.com/t/userscript-show-total-lesson-count/66776
  11. // ==/UserScript==
  12.  
  13. (async function() {
  14. 'use strict';
  15.  
  16. /* global wkof */
  17.  
  18. let scriptId = 'show_total_lesson_count';
  19. let scriptName = 'Show Total Lesson Count';
  20. let wkBatchSize = 0;
  21. let initial_load = true;
  22. let todaysLessonsCount;
  23. let settings;
  24. let stateStarting = false;
  25. let todaysLessonsFrameLoaded = false;
  26. let navBarCountFrameLoaded = false;
  27.  
  28. let debugLogText = `START: ${scriptName} Debug Log:\n`;
  29. let hasOutputLog = false;
  30. let mainSource = '';
  31.  
  32. function addToDebugLog(message) {
  33. debugLogText += `${new Date().toISOString()}: ${message}\n`;
  34. }
  35.  
  36. function printDebugLog() {
  37. if (!hasOutputLog) console.debug(debugLogText);
  38. hasOutputLog = true;
  39. debugLogText = `START: ${scriptName} Debug Log:\n`;
  40. }
  41.  
  42. if (!window.wkof) {
  43. if (confirm(scriptName + ' requires Wanikani Open Framework.\nDo you want to be forwarded to the installation instructions?')) {
  44. window.location.href = 'https://community.wanikani.com/t/instructions-installing-wanikani-open-framework/28549';
  45. }
  46. return;
  47. }
  48.  
  49. const wkofTurboEventsScriptUrl = 'https://update.greasyfork.org/scripts/501980/1419628/Wanikani%20Open%20Framework%20Turbo%20Events.user.js';
  50. addToDebugLog(`Attempting to load the TurboEvents library script...`)
  51. await wkof.load_script(wkofTurboEventsScriptUrl, /* use_cache */ true);
  52. addToDebugLog(`TurboEvents library script should be loaded in`)
  53.  
  54. wkof.ready('TurboEvents').then(() => {
  55. addToDebugLog(`Start of TurboEvents ready callback`)
  56. let urlList = [wkof.turbo.common.locations.dashboard, wkof.turbo.common.locations.items_pages, /^https:\/\/www\.wanikani\.com\/(settings|level|radicals|kanji|vocabulary)(\/|\?difficulty=).+\/?$/];
  57.  
  58. wkof.turbo.on.common.urls(() => {
  59. addToDebugLog(`turbo:load has fired, setting globals and calling _start()`)
  60. initial_load = stateStarting = true;
  61. hasOutputLog = todaysLessonsFrameLoaded = navBarCountFrameLoaded = false;
  62. _start();
  63. }, urlList);
  64. wkof.turbo.on.event.before_frame_render((e) => {
  65. addToDebugLog(`turbo:before-frame-render has fired for "#${e.target.id}"`)
  66. if (['todays-lessons-frame', 'lesson-and-review-count-frame'].includes(e.target.id)) {
  67. hasOutputLog = todaysLessonsFrameLoaded = navBarCountFrameLoaded = false;
  68. }
  69. }, { urls: urlList, noTimeout: true });
  70. wkof.turbo.on.event.frame_load(async (e) => {
  71. addToDebugLog('turbo:frame-load has fired')
  72. if (e.target.id === 'todays-lessons-frame') {
  73. addToDebugLog('turbo:frame-load is for "#todays-lessons-frame"')
  74. todaysLessonsFrameLoaded = true;
  75. mainSource = `turbo:frame-load for "#todays-lessons-frame"`;
  76. await main();
  77. }
  78. else if (e.target.id === 'lesson-and-review-count-frame') {
  79. addToDebugLog('turbo:frame-load is for "#lesson-and-review-count-frame"')
  80. navBarCountFrameLoaded = true;
  81. mainSource = `turbo:frame-load is for "#lesson-and-review-count-frame"`;
  82. await main();
  83. }
  84. else {
  85. addToDebugLog(`turbo:frame-load was for "#${e.target.id}", doing nothing...`)
  86. }
  87. mainSource = '';
  88. }, { urls: urlList });
  89. });
  90.  
  91. if (settings.enableDebugging) printDebugLog();
  92.  
  93. function _start() {
  94. addToDebugLog(`Starting...`)
  95. wkof.include('Settings, Menu, Apiv2');
  96. wkof.ready('Settings, Menu, Apiv2').then(loadSettings).then(insertMenu).then(main);
  97. }
  98.  
  99. function loadSettings() {
  100. addToDebugLog(`Loading settings...`)
  101. wkBatchSize = wkof.user.preferences.lessons_batch_size;
  102.  
  103. let defaults = {
  104. showTotalOnly: false,
  105. setOwnPreferredDaily: false,
  106. preferredDailyAmount: wkBatchSize * 3,
  107. enableDebugging: true,
  108. };
  109.  
  110. return wkof.Settings.load(scriptId, defaults).then(function(wkof_settings) {settings = wkof_settings;});
  111. }
  112.  
  113. function insertMenu() {
  114. addToDebugLog(`Inserting menu...`)
  115. let config = {
  116. name: scriptId,
  117. submenu: 'Settings',
  118. title: scriptName,
  119. on_click: openSettings
  120. };
  121.  
  122. wkof.Menu.insert_script_link(config);
  123. mainSource = `_start() -> loadSettings() -> insertMenu()`;
  124. }
  125.  
  126. function openSettings() {
  127. let config = {
  128. script_id: scriptId,
  129. title: scriptName,
  130. on_save: main,
  131. content: {
  132. showTotalOnly: {
  133. type: 'checkbox',
  134. label: 'Show Only Total Lesson Count',
  135. hover_tip: `Changes display between "<today's lesson count> / <total lesson count>" and just "<total lesson count>"`,
  136. default: false,
  137. },
  138. setOwnPreferredDaily: {
  139. type: 'checkbox',
  140. label: 'Set Your Own Daily Lesson Count',
  141. hover_tip: `Choose whether to display the value you set as your daily lesson count or not`,
  142. default: false,
  143. },
  144. preferredDailyAmount: {
  145. type: 'number',
  146. label: 'Preferred Daily Lesson Amount',
  147. hover_tip: `The number you want displayed for "Today's Lessons". If you use the Wanikani setting, set this to match. Maximum of 100. NOTE: this does not actually change the number of available lessons.`,
  148. default: wkBatchSize * 3,
  149. min: 0,
  150. max: 100,
  151. },
  152. enableDebugging: {
  153. type: 'checkbox',
  154. label: 'Enable console debugging',
  155. hover_tip: `Enable output of debugging info to console.debug()`,
  156. default: true,
  157. }
  158. }
  159. };
  160.  
  161. let dialog = new wkof.Settings(config);
  162. dialog.open();
  163. }
  164.  
  165. async function getCountContainers() {
  166. let dashboardTileCountContainer = document.querySelector('.todays-lessons__count-text .count-bubble');
  167. let navBarCountContainer = document.querySelector('.lesson-and-review-count__count');
  168.  
  169. if (initial_load && (dashboardTileCountContainer || navBarCountContainer)) {
  170. let container = dashboardTileCountContainer ?? navBarCountContainer;
  171. todaysLessonsCount = parseInt(container.textContent);
  172. initial_load = false;
  173. }
  174.  
  175. return [dashboardTileCountContainer, navBarCountContainer];
  176. }
  177.  
  178. async function main() {
  179. addToDebugLog(`Main function is executing... source of start: ${mainSource}`)
  180. if (!settings) {
  181. addToDebugLog('We do not have settings, setting timeout on _start()');
  182. if (!stateStarting) { stateStarting = true; setTimeout(_start, 50); }
  183. else addToDebugLog(`Did not set timeout due to already being in starting state`);
  184. return;
  185. }
  186. addToDebugLog(`We have settings`)
  187. stateStarting = false;
  188. let summary_data = await wkof.Apiv2.get_endpoint('summary');
  189. let totalLessonCount = summary_data.lessons[0].subject_ids.length;
  190. let lessonCountContainers;
  191. if (todaysLessonsFrameLoaded || navBarCountFrameLoaded) {
  192. addToDebugLog(`Frame(s) loaded`)
  193. lessonCountContainers = await getCountContainers();
  194. }
  195. else {
  196. addToDebugLog('No frames loaded')
  197. return;
  198. }
  199. let todaysCountForDisplay = todaysLessonsCount;
  200.  
  201. if (lessonCountContainers.every(node => node == null)) {
  202. addToDebugLog('No nodes in containers')
  203. return;
  204. }
  205. addToDebugLog('At least one container exists')
  206.  
  207. if (isNaN(todaysLessonsCount)) {
  208. todaysCountForDisplay = 0;
  209. }
  210. else {
  211. if (settings.setOwnPreferredDaily) todaysCountForDisplay = todaysLessonsCount - (wkBatchSize * 3 - settings.preferredDailyAmount);
  212. }
  213.  
  214. if (lessonCountContainers[0]) lessonCountContainers[0].textContent = settings.showTotalOnly ? totalLessonCount : todaysCountForDisplay + ' / ' + totalLessonCount;
  215. if (lessonCountContainers[1]) lessonCountContainers[1].textContent = settings.showTotalOnly ? totalLessonCount : todaysCountForDisplay;
  216.  
  217. if (todaysCountForDisplay === 0) {
  218. // hide the start button if it is not already, TODO: disable nav bar button if it is not already
  219. let startButton = document.querySelector('.todays-lessons-button--start')
  220. if (startButton && startButton.checkVisibility()) {
  221. startButton.style.display = 'none';
  222. }
  223. }
  224.  
  225. // hide "Today's" subtitle
  226. let lessonSubtitle = document.querySelector('.todays-lessons__subtitle');
  227.  
  228. if (lessonSubtitle && lessonSubtitle.checkVisibility()) {
  229. lessonSubtitle.style.display = 'none';
  230. }
  231.  
  232. if (settings.enableDebugging) printDebugLog();
  233. }
  234. })();