您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Shows top leeches on dashboard (replaces critical items) and all leeches on a dedicated page (replaces critical items)
// ==UserScript== // @name WaniKani Dashboard Leech List Unburnable Edit // @namespace https://www.wanikani.com // @description Shows top leeches on dashboard (replaces critical items) and all leeches on a dedicated page (replaces critical items) // @author ukebox (edited by Pep95) // @version 2.1.0 // @require https://code.jquery.com/jquery-3.3.1.min.js#sha256=FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8= // @include https://www.wanikani.com/dashboard // @include https://www.wanikani.com/ // @include https://www.wanikani.com/critical-items // @grant none // @run-at document-end // ==/UserScript== /* jshint esversion: 6 */ (function() { 'use strict'; let sumval; let dom = {}; dom.$ = jQuery.noConflict(true); if (!window.wkof) { let response = confirm('WaniKani Dashboard Leech List script requires WaniKani Open Framework.\n Click "OK" to be forwarded to installation instructions.'); if (response) { window.location.href = 'https://community.wanikani.com/t/instructions-installing-wanikani-open-framework/28549'; } return; } const leechThreshold = 1; const config = { wk_items: { options: { review_statistics: true, assignments: true }, filters: { srs: {value: '-1,0,9', invert: true} } } }; const srs_stages = [ 'Initiate', 'Apprentice 1', 'Apprentice 2', 'Apprentice 3', 'Apprentice 4', 'Guru 1', 'Guru 2', 'Master', 'Enlightened', 'Burned' ]; window.wkof.include('Menu,Settings,ItemData'); window.wkof.ready('Menu,Settings,ItemData').then(load_settings).then(install_menu).then(getItems).then(determineLeeches).then(updatePage); function getItems() { return window.wkof.ItemData.get_items(config); } function determineLeeches(items) { return items.filter(item => isLeech(item)); } function summer( item ) { var sum = 0; console.log( "sum1: "+sum+" "+item); for( var impcnt in item ) { console.log( "sum1: "+sum+" what is item.impcnt: "+item.impcnt ); if( item.hasOwnProperty( impcnt ) && item.impcnt == 1) { sum += parseFloat( item[impcnt] ); console.log( "sum1: "+sum+" "+item ); } } return sum; } function isLeech(item) { if (item.review_statistics === undefined) { return false; } let reviewStats = item.review_statistics; let meaningScore = computeLeechScore(reviewStats.meaning_incorrect, reviewStats.meaning_current_streak); let readingScore = computeLeechScore(reviewStats.reading_incorrect, reviewStats.reading_current_streak); item.leech_score = Math.max(meaningScore, readingScore); if (item.assignments.srs_stage == 9) { meaningScore = 0; readingScore = 0; } if (meaningScore < readingScore) { item.highestincorrect = reviewStats.reading_incorrect; item.highestincorrectstreak = reviewStats.reading_current_streak; } else { item.highestincorrect = reviewStats.meaning_incorrect; item.highestincorrectstreak = reviewStats.meaning_current_streak; } item.mustBurn = (item.highestincorrect - item.highestincorrectstreak) + item.assignments.srs_stage >= 9; if (item.mustBurn){ item.impossible = "不可能"; item.impcnt = 1; } else { item.impossible = " "; item.impcnt = 0; } item.srsstagename = srs_stages[item.assignments.srs_stage]; return meaningScore >= leechThreshold || readingScore >= leechThreshold; } function computeLeechScore(incorrect, currentStreak) { return incorrect / Math.pow((currentStreak || 0.5), 1.5); } function updatePage(items) { let is_dashboard = window.location.pathname !== "/critical-items"; let totalleeches = items.length; if (is_dashboard) { items = items.sort((a, b) => (b.highestincorrect - a.highestincorrect)||(a.highestincorrectstreak - b.highestincorrectstreak)).slice(0,10); } else { items = items.sort((a, b) => (b.highestincorrect - a.highestincorrect)||(a.highestincorrectstreak - b.highestincorrectstreak)); } console.log(items); makeLeechList(items, is_dashboard, totalleeches); } function round(number, decimals) { return +(Math.round(number + "e+" + decimals) + "e-" + decimals); } function makeLeechList(items, for_dashboard, totalleeches) { let rows = ""; let textstuff = ""; let sumval = 0; let temp = ""; //writer = ""; let d = new Date(); //temp = "Leeches " + d.getdate() + "-" + d.getMonth()+1 + "-" + d.getFullYear + " " + d.getHours() + ":" + d.getMinutes() + ".txt"; //textstuff = "You have " + totalleeches + " leeches as of " + d.getdate() + "-" + d.getMonth()+1 + "-" + d.getFullYear + " " + d.getHours() + ":" + d.getMinutes() + "\r\n\r\n"; temp = "Leeches as of Now.txt"; textstuff = "You have " + totalleeches + " leeches as of now.\r\n\r\n"; //set fso = CreateObject("Scripting.FileSystemObject"); //set s = fso.CreateTextFile(temp, True); items.forEach(item => { let type = item.assignments.subject_type; //use slug by default (for kanji and vocab) let representation = item.data.slug; //The slug of a radical just has its name, we want the actual symbol. if (type === 'radical') { if (item.data.characters) { //use characters for radicals when possible representation = item.data.characters; } else if (item.data.character_images) { //use SVG image for scalability let image_data = item.data.character_images.find(x => x.content_type === "image/svg+xml" && x.metadata.inline_styles); if (image_data) { representation = `<img style="height: 1em; width: 1em; filter: invert(100%);" src="${image_data.url}" />`; } } } if (for_dashboard) { rows+=`<li class="subject-character-grid__item"> <a class="subject-character subject-character--${type} subject-character--grid subject-character--unlocked title="${representation}" href="${item.data.document_url}"> <div class="subject-character__content"> <span class=subject-character__characters lang="ja">${representation}</span> <div class="subject-character__info"> <span class="subject-character__additional-info"> <table style="width:150px"> <td width="40%" align="right"> ${item.impossible} </td> <td width="30%" align="right">${item.highestincorrect}/${item.highestincorrectstreak}</td> <td width="30%" align="right">${round(item.leech_score, 2)}</td> </table> </span> </div> </div> </a> </li>`; } else { rows+=`<li class="subject-character-grid__item"> <a class="subject-character subject-character--${type} subject-character--grid subject-character--unlocked title="${representation}" href="${item.data.document_url}"> <div class="subject-character__content"> <span class=subject-character__characters lang="ja">${representation}</span> <div class="subject-character__info"> <span class="subject-character__additional-info"> <table style="width:300px"> <td width="25%" align="right"> ${item.impossible} </td> <td width="5%" align="left"></td><td width="30%" align="left"> ${item.srsstagename} </td> <td width="15%" align="right">${item.highestincorrect}/${item.highestincorrectstreak}</td> <td width="15%" align="right">${round(item.leech_score, 2)}</td> </table> </span> </div> </div> </a> </li>`; } if (for_dashboard == 0 && wkof.settings.LeechListUnburnable.CreateTxt) { textstuff+=`${representation}\r\n`; } if (item.impcnt == 1) { sumval = sumval + 1; } }); if (for_dashboard == 0 && wkof.settings.LeechListUnburnable.CreateTxt) { var a = document.createElement("a"); a.href = "data:text/plain;charset=utf-8," + encodeURIComponent(textstuff); a.download = temp; a.click(); } if (for_dashboard == 1) { let sectionContent = `<div class="wk-panel__header"> <h2 class="wk-panel__title">${for_dashboard ? 'Top ' : ''}Leeches${for_dashboard ? ' (' + totalleeches + ')' : ''}</h2> </div> <div class="wk-panel__content"> <div class="dashboard-lists"> <div class="subject-character-grid subject-character-grid--single-column"> <ol class="subject-character-grid__items"> ${rows} </ol> </div> <div class="dashboard-lists__buttons"> <a class="wk-button wk-button--default" ${for_dashboard ? 'href="/critical-items"' : ''}> <span class="wk-button__text"> ${for_dashboard ? 'See More Leeches...' : totalleeches + ' leeches total (' + sumval + ' burn-only leeches)'} </span> </a> </div> </div> </div>`; dom.$('.wk-panel--dashboard-list-critical').html(sectionContent); } else { let sectionContent = `<ol class="subject-character-grid__items"> ${rows} <li class="subject-character-grid__item"> <a class="subject-character subject-character--grid subject-character--unlocked" style="background-color:#F4F4F4;"> <div class="subject-character__content"> <div class="subject-character__info" style="margin: 0 auto;"> <span class="subject-character__additional-info"> <div style="width: 100%; text-align: center; color: #333;"> ${totalleeches} LEECHES TOTAL (${sumval} BURN-ONLY LEECHES) </div> </span> </div> </div> </a> </li> </ol>`; dom.$('.subject-character-grid').html(sectionContent); dom.$('.page-header__title-text').html("Leech List"); dom.$('.wk-text').html(totalleeches + " leeches in total (of which " + sumval + " burn-only leeches)"); dom.$('.subject-character-grid').css('border-radius', '6px'); dom.$('.subject-character-grid').css('overflow', 'hidden'); } } // Load settings and set defaults function load_settings() { var defaults = { CreateTxt: 'false', }; return wkof.Settings.load('LeechListUnburnable', defaults); } // Installs the options button in the menu function install_menu() { var config = { name: 'leech_list_unburnable', submenu: 'Settings', title: 'Leech List Unburnable Edit', on_click: open_settings }; wkof.Menu.insert_script_link(config); } // Create the options function open_settings(items) { var config = { script_id: 'LeechListUnburnable', title: 'Leech List Unburnable Edit', content: { CreateTxt: { type: 'checkbox', label: 'Create Txt File', hover_tip: 'Create Txt File when loading the Critical Items Page', default: 'false' } } } var dialog = new wkof.Settings(config); dialog.open(); } // Returns a promise and a resolve function function new_promise() { var resolve, promise = new Promise((res, rej)=>{resolve = res;}); return [promise, resolve]; } })(); /* item.startleech = 9 - (item.assignments.srs_stage - item.highestincorrectstreak); switch(item.startleech) { case 8: if (item.highestincorrect>18) { item.impossible = "不可能" item.impcnt = 1 } else { item.impossible = " " item.impcnt = 0 } break; case 7: if (item.highestincorrect>14) { item.impossible = "不可能" item.impcnt = 1 } else { item.impossible = " " item.impcnt = 0 } break; case 6: if (item.highestincorrect>11) { item.impossible = "不可能" item.impcnt = 1 } else { item.impossible = " " item.impcnt = 0 } break; case 5: if (item.highestincorrect>7) { item.impossible = "不可能" item.impcnt = 1 } else { item.impossible = " " item.impcnt = 0 } break; case 4: if (item.highestincorrect>5) { item.impossible = "不可能" item.impcnt = 1 } else { item.impossible = " " item.impcnt = 0 } break; case 3: if (item.highestincorrect>2) { item.impossible = "不可能" item.impcnt = 1 } else { item.impossible = " " item.impcnt = 0 } break; case 2: if (item.highestincorrect>0) { item.impossible = "不可能" item.impcnt = 1 } else { item.impossible = " " item.impcnt = 0 } break; case 1: if (item.highestincorrect>0) { item.impossible = "不可能" item.impcnt = 1 } else { item.impossible = " " item.impcnt = 0 } break; default: item.impossible = " " item.impcnt = 0 } */ /* switch(item.assignments.srs_stage) { case 8: item.srsstagename = "Enlightened"; break; case 7: item.srsstagename = "Master"; break; case 6: item.srsstagename = "Guru 2"; break; case 5: item.srsstagename = "Guru 1"; break; case 4: item.srsstagename = "Apprentice 4"; break; case 3: item.srsstagename = "Apprentice 3"; break; case 2: item.srsstagename = "Apprentice 2"; break; case 1: item.srsstagename = "Apprentice 1"; break; default: item.srsstagename = "Exception"; break; } */ //var summed = summer( item ); //console.log( "sum: "+summed ); /* rows+=`<tr class="${type}"> <td> <a href="${item.data.document_url}"> <span lang="ja">${representation}</span> <span class="pull-right"> <table style="width:150px"> <td width="40%" align="right"> ${item.impossible} </td> <td width="30%" align="right">${item.highestincorrect}/${item.highestincorrectstreak}</td> <td width="30%" align="right">${round(item.leech_score, 2)}</td> </table> </span> </a> </td> </tr>`; */ /* rows+=`<tr class="${type}"> <td> <a href="${item.data.document_url}"> <span lang="ja">${representation}</span> <span class="pull-right"> <table style="width:300px"> <td width="25%" align="right"> ${item.impossible} </td> <td width="5%" align="left"></td><td width="30%" align="left"> ${item.srsstagename} </td> <td width="15%" align="right">${item.highestincorrect}/${item.highestincorrectstreak}</td> <td width="15%" align="right">${round(item.leech_score, 2)}</td> </table> </span> </a> </td> </tr>`; */