您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Displays your level for each SRS stage.
// ==UserScript== // @name Wanikani: Levels by SRS // @namespace http://tampermonkey.net/ // @version 1.1.7 // @description Displays your level for each SRS stage. // @author Kumirei // @match https://www.wanikani.com/dashboard // @match https://www.wanikani.com // @include *preview.wanikani.com* // @grant none // ==/UserScript== /*jshint esversion: 8 */ ;(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 = {} let item for (var i = 0; i < data.length; i++) { 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[ ['Ini', 'App', 'App', 'App', 'App', 'Gur', 'Gur', 'Mas', 'Enl', 'Bur'][ item.assignments.srs_stage ] ]++ 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').append(display) } // Update for (let 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); display: flex; justify-content: space-around; } #levels_by_srs > div { display: flex; flex: 1; justify-content: center; } #levels_by_srs .level_label { font-size: 16px; margin-right: 5px; } #levels_by_srs .value { font-size: 16px; font-weight: normal; } #levels_by_srs.dark_theme { background: #232629; } #levels_by_srs.dark_theme > div:not(:last-child) { border-right: 1px solid #31363b; margin-right: 5px; } #levels_by_srs.dark_theme > div:last-child { border-right: 1px solid transparent; } .srs-progress > ul > li { border-radius: 0 !important; } </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 ) } })()