WaniKani Lesson Cap

Limits the amount of lessons you can do with your current review queue.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         WaniKani Lesson Cap
// @namespace    https://github.com/valeth
// @version      0.6.4
// @description  Limits the amount of lessons you can do with your current review queue.
// @author       valeth
// @match        https://www.wanikani.com/dashboard
// @match        https://www.wanikani.com/lesson
// @match        https://www.wanikani.com/lesson/session
// @grant        none
// @run-at       document-end
// @license      MIT
// ==/UserScript==

/* jshint ignore:start */

const debugging = false;
// Generated by CoffeeScript 2.0.2
(function() {
  // =======[ WKOF Guard ]=======

  // coffeelint: disable=max_line_length
  var btn_continue, calculate_score, confirmed, continue_button, default_settings, get_items, get_or_wait, install_menu, install_settings, log, render_all, render_available, render_results, round2, settings, settings_dialog, srs_levels, start_button, titleize, update;

  if (window.wkof == null) {
    confirmed = confirm('WaniKani Lesson Cap requires the WaniKani Open Framework.\nDo you want to be forwarded to the installation instructions?');
    if (confirmed) {
      window.location.href = "https://community.wanikani.com/t/instructions-installing-wanikani-open-framework/28549";
    }
    return;
  }

  // coffeelint: enable=max_line_length

  // =======[ Globals ]=======
  btn_continue = void 0;

  settings_dialog = void 0;

  default_settings = {
    max_score: 100
  };

  srs_levels = [
    {
      stage: 1,
      rating: 6,
      ident: 'apprentice1'
    },
    {
      stage: 2,
      rating: 3,
      ident: 'apprentice2'
    },
    {
      stage: 3,
      rating: 1.04,
      ident: 'apprentice3'
    },
    {
      stage: 4,
      rating: 0.51,
      ident: 'apprentice4'
    },
    {
      stage: 5,
      rating: 0.14,
      ident: 'guru1'
    },
    {
      stage: 6,
      rating: 0.07,
      ident: 'guru2'
    },
    {
      stage: 7,
      rating: 0.03,
      ident: 'master'
    },
    {
      stage: 8,
      rating: 0.01,
      ident: 'enlightened'
    }
  ];

  // =======[ Utility functions ]=======
  log = {
    info: function(message) {
      return console.log("[WKLC] " + message);
    },
    error: function(message) {
      return console.error("[WKLC] " + message);
    },
    debug: function(message) {
      if (debugging) {
        return console.log("[WKLC] " + message);
      }
    },
    inspect: function(thing) {
      if (debugging) {
        return console.debug(thing);
      }
    }
  };

  // Format a given string into "titleized" format.
  // Example:
  //   someIdentifier1 -> Some Identifier 1
  titleize = function(string) {
    var char, i, len, ref, tmp;
    tmp = string[0].toUpperCase();
    ref = string.slice(1);
    for (i = 0, len = ref.length; i < len; i++) {
      char = ref[i];
      if (char === char.toUpperCase()) {
        tmp += ` ${char}`;
      } else {
        tmp += char;
      }
    }
    return tmp;
  };

  round2 = function(num) {
    return Math.round(num * 100) / 100;
  };

  get_or_wait = function(key, callback) {
    var value;
    value = wkof.get_state(key);
    if (value != null) {
      return callback(value);
    }
    return wkof.wait_state(key, "*", function(value, _) {
      return callback(value);
    });
  };

  // =======[ Rendering ]=======
  start_button = function(action) {
    var btn_start, lesson_queue_count;
    btn_start = $("#start-session > a");
    if (btn_start[0] == null) {
      return;
    }
    lesson_queue_count = $("#lesson-queue-count");
    switch (action) {
      case "disable":
        log.info("Disabling lesson start button...");
        btn_start.addClass("wklc-force-hidden");
        return lesson_queue_count.addClass("wklc-lesson-count");
      case "enable":
        log.info("Enabling lesson start button...");
        btn_start.removeClass("wklc-force-hidden");
        return lesson_queue_count.removeClass("wklc-lesson-count");
    }
  };

  continue_button = function(action) {
    if (btn_continue == null) {
      btn_continue = $("#lesson-ready-continue");
    }
    if (btn_continue[0] == null) {
      return;
    }
    switch (action) {
      case "disable":
        log.info("Disabling lesson continue button...");
        return btn_continue.remove();
      case "enable":
        log.info("Enabling lesson continue button...");
        return $("#screen-lesson-ready .btn-set").append(btn_continue);
    }
  };

  render_all = function() {
    return get_items(function(score, stats) {
      var batch_size, batches, max_score, remaining_score, score_per_item;
      render_results(score, stats);
      batch_size = $.jStorage.get("l/batchSize");
      max_score = settings("max_score");
      remaining_score = max_score - score;
      score_per_item = batch_size * (srs_levels[0].rating / 2);
      batches = Math.floor(remaining_score / score_per_item);
      if (batches >= 1) {
        start_button("enable");
      }
      if (batches >= 2) {
        continue_button("enable");
      }
      return render_available(batch_size, batches);
    });
  };

  render_results = function(score, stats) {
    var max_score, wklc, wklc_items;
    if ($("#lessons-summary")[0] == null) {
      return;
    }
    log.debug("Rendering results...");
    wklc = $(".wklc");
    if (wklc[0] != null) {
      wklc.remove();
    }
    max_score = settings("max_score");
    wklc_items = stats.reduce(function(acc, stat, index) {
      return acc += `<li class='wklc-item wklc-${srs_levels[index].ident}'\n    title='${titleize(srs_levels[index].ident)}'>\n  <span>${round2(stat.count)}</span>\n  <span>(${round2(stat.score)})</span>\n</li>`;
    }, "");
    return $("#lessons-summary").prepend($(`<div class="wklc">\n  <ul class="wklc-items">${wklc_items}</ul>\n  <div class='wklc-right'>\n    <div class='wklc-item wklc-score'>\n      <span>Score:</span>\n      <span>${round2(score)}</span> / <span>${max_score}</span>\n    </div>\n    <button class='wklc-item wklc-btn-settings'\n            title='Settings'>⚙</button>\n  </div>\n</div>`));
  };

  render_available = function(batch_size, batches) {
    var allowed_lessons, lessons_queue_count, title;
    if ($("#lessons-summary")[0] == null) {
      return;
    }
    allowed_lessons = $(".wklc-allowed-lessons");
    if (allowed_lessons[0] != null) {
      allowed_lessons.remove();
    }
    lessons_queue_count = +$("#lesson-queue-count").text();
    if (lessons_queue_count === 0 && !debugging) {
      return;
    }
    title = `This is the amount of batches of ${batch_size}\nlessons you can do without exceeding the max score.`;
    allowed_lessons = $(`<span class='wklc-allowed-lessons' title='${title}'>\n  ${batches + ' Available'}\n</span>`);
    if (batches < 1) {
      allowed_lessons.addClass("disabled");
      allowed_lessons.attr("title", "Lessons button disabled because you can do\nless than one session before exceeding max score.");
    }
    return $("#start-session").append(allowed_lessons);
  };

  // ======[ API Requests and Calculations ]=======
  get_items = function(callback) {
    return wkof.ItemData.get_items({
      wk_items: {
        options: {
          assignments: true
        },
        filters: {
          srs: {
            value: ["lock", "burn"],
            invert: true
          },
          level: "1 to +0" // from first level to current
        }
      }
    }).then(function(items) {
      var score, stats;
      [score, stats] = calculate_score(items);
      return callback(score, stats);
    });
  };

  calculate_score = function(items) {
    var stats, total_score;
    stats = srs_levels.map(function() {
      return {
        count: 0,
        score: 0.0
      };
    });
    items.forEach(function(cur) {
      var stage;
      stage = cur.assignments.srs_stage - 1;
      if (stage < 0 || stage > 7) {
        return;
      }
      stats[stage].count += 1;
      return stats[stage].score = (stats[stage].count * srs_levels[stage].rating) / 2;
    });
    wkof.set_state("wklc.stats", stats);
    total_score = stats.reduce(function(acc, cur) {
      return acc += round2(cur.score);
    }, 0);
    wkof.set_state("wklc.current_score", total_score);
    return [total_score, stats];
  };

  // =======[ Setup ]=======
  update = function() {
    // need to disable buttons on every update again
    start_button("disable");
    continue_button("disable");
    return render_all();
  };

  install_menu = function() {
    var open_settings;
    open_settings = function() {
      if (settings_dialog != null) {
        return settings_dialog.open();
      }
    };
    wkof.Menu.insert_script_link({
      script_id: "wklc",
      submenu: "Settings",
      title: "WaniKani Lesson Cap",
      on_click: open_settings
    });
    return $(document).on("click", ".wklc-btn-settings", open_settings);
  };

  settings = function(key) {
    return wkof.settings.wklc[key];
  };

  install_settings = function() {
    var save_settings;
    save_settings = function() {
      wkof.Settings.save("wklc");
      update();
      return log.info("Settings saved");
    };
    wkof.Settings.load("wklc", default_settings);
    return settings_dialog = new wkof.Settings({
      script_id: "wklc",
      title: "WaniKani Lesson Cap",
      on_save: save_settings,
      settings: {
        pg_general: {
          type: "page",
          label: "General",
          content: {
            max_score: {
              type: "number",
              label: "Max score"
            }
          }
        }
      }
    });
  };

  $(document).on("click", "#batch-items .active-quiz", update);

  $(document).on("click", "#quiz-ready-continue", update);

  $(document).ready(function() {
    var modules;
    modules = "Apiv2, ItemData, Menu, Settings";
    // coffeelint: disable=max_line_length
    wkof.load_css("https://raw.githubusercontent.com/valeth/wanikani-lesson-cap/wkof/compiled/style.css");
    // coffeelint: enable=max_line_length
    wkof.include(modules);
    wkof.ready("Menu").then(install_menu);
    wkof.ready("Settings").then(install_settings);
    return wkof.ready(modules).then(update);
  });

}).call(this);


/* jshint ignore:end */