Wanikani: Levels by SRS

Displays your level for each SRS stage.

2019-07-17 या दिनांकाला. सर्वात नवीन आवृत्ती पाहा.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्क्रिप्ट व्यवस्थापक एक्स्टेंशन इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्क्रिप्ट व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्टाईल व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

// ==UserScript==
// @name         Wanikani: Levels by SRS
// @namespace    http://tampermonkey.net/
// @version      1.1.0
// @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, 0, 0], App: [0, 0, 0], Gur: [0, 0, 0], Mas: [0, 0, 0], Enl: [0, 0, 0], Bur: [0, 0, 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)]++;
								else by_srs['Ini']++;
								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]][0]+1) {
										srs_levels[types[j]][0]++;
								}
								else if (1-cumulative/by_srs.total <= wkof.settings.levels_by_srs.threshold/100 && i == srs_levels[types[j]][0]+1) {
										srs_levels[types[j]][1] = 1-cumulative/by_srs.total;
										srs_levels[types[j]][2] = by_srs.total;
								}
								cumulative += count;
						}
				}
				return srs_levels;
		}

		// Updates the display element
		function update_display(srs_levels) {
				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++) {
						var elem = $(display).find('.'+types[i]+' span.value')[0];
						elem.innerText = srs_levels[types[i]][0];
						elem.parentElement.setAttribute('title', Math.floor(srs_levels[types[i]][1]*100) + '% to level ' + (srs_levels[types[i]][0]+1) + ' (' + Math.round(srs_levels[types[i]][1] * srs_levels[types[i]][2]) + ' of ' + srs_levels[types[i]][2] + ')');
				}
		}

		// 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;
		}
})();