Wanikani: Levels by SRS

Displays your level for each SRS stage.

当前为 2019-07-07 提交的版本,查看 最新版本

// ==UserScript==
// @name         Wanikani: Levels by SRS
// @namespace    http://tampermonkey.net/
// @version      1.0.1
// @description  Displays your level for each SRS stage.
// @author       Kumirei
// @match        https://www.wanikani.com/dashboard
// @match        https://www.wanikani.com
// @grant        none
// ==/UserScript==

(function() {
    //check that the Wanikani Framework is installed
    var script_name = 'Levels By SRS';
    if (!window.wkof) {
        if (confirm(script_name+' requires Wanikani Open Framework.\nDo you want to be forwarded to the installation instructions?'))
            window.location.href = 'https://community.wanikani.com/t/instructions-installing-wanikani-open-framework/28549';
        return;
    }
    //if it's installed then do the stuffs
    else {
        wkof.include('Menu,Settings,ItemData');
        wkof.ready('Menu,Settings,ItemData')
            .then(load_settings)
            .then(install_menu)
            .then(add_css)
            .then(fetch_and_update);
    }

    // Fetches items and updates display
    function fetch_and_update() {
        fetch_items()
            .then(process_items)
            .then(update_display);
    }

    // Fetches the relevant items
    function fetch_items() {
        var [promise, resolve] = new_promise();
        var config = {
            wk_items: {
                options: {assignments: true},
                filters: {level: "1..+0"}
            }
        };
        wkof.ItemData.get_items(config).then(resolve);
        return promise;
    }

    // Retreives the levels by srs
    function process_items(data) {
        // Sort by level
        var levels = {};
        for (var i=0; i<data.length; i++) {
            var item = data[i];
            var level = item.data.level;
            if (!levels[level]) levels[level] = [];
            levels[level].push(item);
        }
        // Go through items level by level
        var srs_levels = {Ini: 0, App: 0, Gur: 0, Mas: 0, Enl: 0, Bur: 0};
        for (i=1; i<wkof.user.level+1; i++) {
            // Get counts for level
            var by_srs = {Ini: 0, App: 0, Gur: 0, Mas: 0, Enl: 0, Bur: 0, total: 0};
            for (var j=0; j<levels[i].length; j++) {
                item = levels[i][j];
                if (item.assignments) by_srs[item.assignments.srs_stage_name.slice(0, 3)]++;
                by_srs.total++;
            }
            // Check if srs_level should be increased
            var types = ['Ini', 'App', 'Gur', 'Mas', 'Enl', 'Bur'];
            var cumulative = 0;
            for (j=0; j<types.length; j++) {
                var count = by_srs[types[j]];
                if (1-cumulative/by_srs.total >= wkof.settings.levels_by_srs.threshold/100 && i == srs_levels[types[j]]+1) {
                    srs_levels[types[j]]++;
                }
                cumulative += count;
            }
        }
        console.log(srs_levels);
        return srs_levels;
    }

    // Updates the display element
    function update_display(srs_levels) {
        console.log('update display');
        var types = ['App', 'Gur', 'Mas', 'Enl', 'Bur'];
        // If the element doesn't already exist, create it
        var display = $('#levels_by_srs');
        if (!display.length) {
            display = $('<div id="levels_by_srs"'+(is_dark_theme() ? ' class="dark_theme"' : '')+'></div>');
            for (var i=0; i<types.length; i++) display.append('<div class="'+types[i]+'"><span class="level_label">Level: </span><span class="value"></span></div>');
            $('.srs-progress').after(display);
        }
        // Update
        for (i=0; i<types.length; i++) $(display).find('.'+types[i]+' span.value')[0].innerText = srs_levels[types[i]];
    }

    // Load stored settings or set defaults
    function load_settings() {
        var defaults = {threshold: 90};
        return wkof.Settings.load('levels_by_srs', defaults);
    }

    // Installs the options button in the menu
    function install_menu() {
        var config = {
            name: 'levels_by_srs',
            submenu: 'Settings',
            title: 'Levels By SRS',
            on_click: open_settings
        };
        wkof.Menu.insert_script_link(config);
    }

    // Create the options
    function open_settings(items) {
        var config = {
            script_id: 'levels_by_srs',
            title: 'Levels By SRS',
            on_save: fetch_and_update,
            content: {
                threshold: {
                    type: 'number',
                    label: 'Threshold',
                    hover_tip: 'Percentage to consider level done',
                    default: 90,
                }
            }
        }
        var dialog = new wkof.Settings(config);
        dialog.open();
    }

    // Adds the script's CSS to the page
    function add_css() {
        $('head').append('<style id="levels_by_srs_CSS">'+
                         '#levels_by_srs {'+
                         '    background: #434343;'+
                         '    border-radius: 0 0 3px 3px;'+
                         '    height: 30px;'+
                         '    line-height: 30px;'+
                         '    color: rgb(240, 240, 240);'+
                         '    font-size: 16px;'+
                         '}'+
                         '#levels_by_srs > div {'+
                         '    width: calc(20% - 1px);'+
                         '    display: inline-block;'+
                         '    text-align: center;'+
                         '}'+
                         '#levels_by_srs .level_label {'+
                         '    font-weight: bold;'+
                         '}'+
                         '.dashboard > .container > .row > .span12 > section.srs-progress {'+
                         '    margin-bottom: 0 !important;'+
                         '}'+
                         '.srs-progress > ul > li {'+
                         '    border-radius: 0 !important;'+
                         '}'+
                         '#levels_by_srs.dark_theme {'+
                         '    background: #232629;'+
                         '    box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.7), 2px 2px 2px rgba(0, 0, 0, 0.7);'+
                         '    margin: 0 3px 3px 3px;'+
                         '}'+
                         '#levels_by_srs.dark_theme > div:not(:last-child) {'+
                         '    border-right: 1px solid #31363b;'+
                         '}'+
                         '</style>');
    }

    // Returns a promise and a resolve function
    function new_promise() {
        var resolve, promise = new Promise((res, rej)=>{resolve = res;});
        return [promise, resolve];
    }

    // Handy little function that rfindley wrote. Checks whether the theme is dark.
    function is_dark_theme() {
        // Grab the <html> background color, average the RGB.  If less than 50% bright, it's dark theme.
        return $('body').css('background-color').match(/\((.*)\)/)[1].split(',').slice(0,3).map(str => Number(str)).reduce((a, i) => a+i)/(255*3) < 0.5;
    }
})();