Shows status of your Wanikani lessons/reviews while in the forums.
当前为
// ==UserScript==
// @name Wanikani Forums Lesson/Review Status
// @namespace rfindley
// @description Shows status of your Wanikani lessons/reviews while in the forums.
// @version 1.0.9
// @include https://community.wanikani.com/*
// @require https://greasyfork.org/scripts/27967-wanikani-forums-global-framework/code/Wanikani%20Forums%20Global%20Framework.js?version=186167
// @copyright 2017+, Robin Findley
// @license MIT; http://opensource.org/licenses/MIT
// @run-at document-end
// @grant none
// ==/UserScript==
window.wkf_lrstatus = {};
(function(gobj) {
var settings = {
show_next_review: true
};
var settings_url = '/scripts/lrstatus';
var randomize_query = 300; // Randomize API query times over a 300 sec period to spread server load.
var next_review = -1;
//-------------------------------------------------------------------
// Let the global script know about our settings page (if we have one)
//-------------------------------------------------------------------
// window.wkf_global.add_script('Lesson/Review Status', settings_url);
var apikey = window.wkf_global.get_apikey();
if (apikey === null) return; // Just in case the auto-redirect doesn't work
// Don't run past this point if we are on a settings screen.
if (window.location.pathname.match(/^\/scripts\//) !== null) return;
//-------------------------------------------------------------------
// Styling info for this script.
//-------------------------------------------------------------------
var css =
'.dashboard_bubble {background-color:#6cf; font-size:0.8em; border-radius:0.5em; padding:0 6px; margin:0 0 0 4px; color:#fff; font-weight:bold;}'+
'.dashboard_bubble.zero {background-color:#bdbdbd;}'+
'#next_review {background-color:#bdbdbd;}'+
'#next_review.zero {background-color:#6cf;}'+
'.float_wkappnav .d-header {height:inherit;}'+
'.float_wkappnav .wanikani-app-nav-container {border-top:1px solid #ccc; line-height:2em;}'+
'.float_wkappnav .wanikani-app-nav ul {padding-bottom:0; margin-bottom:0; border-bottom:inherit;}'+
'.timeline-container:not(.timeline-docked) {margin-top:25px;}';
//-------------------------------------------------------------------
// Display a friendly relative time for the next review.
//-------------------------------------------------------------------
function update_time() {
var timestamp = next_review;
if (timestamp === null) {
$('#next_review').text('none').removeClass('zero');
return;
}
var now = Math.trunc(new Date().getTime()/1000);
var diff = Math.max(0, timestamp-now);
var dd = Math.floor(diff / 86400);
diff -= dd*86400;
var hh = Math.floor(diff / 3600);
diff -= hh*3600;
var mm = Math.floor(diff / 60);
diff -= mm*60;
var ss = diff;
var text, next_update;
var is_now = false;
if (dd > 0) {
text = dd+' day'+(dd===1?'':'s')+', '+hh+' hour'+(hh===1?'':'s');
next_update = mm*60+ss+1;
} else if (hh > 0) {
text = hh+' hour'+(hh===1?'':'s')+', '+mm+' min'+(mm===1?'':'s');
next_update = ss;
} else if (mm > 0 || ss > 15) {
if (ss > 0) mm++;
text = mm+' min'+(mm===1?'':'s');
next_update = ss;
} else {
text = 'Now';
next_update = -1;
is_now = true;
}
var nr = $('#next_review');
nr.text(text);
if (is_now)
nr.addClass('zero');
else
nr.removeClass('zero');
if (next_update >= 0) setTimeout(update_time, (next_update+1)*1000);
}
//-------------------------------------------------------------------
// Update the lesson/review count info on the screen.
//-------------------------------------------------------------------
function update_counts(lessons, reviews) {
var lc = $('#lesson_count');
var rc = $('#review_count');
if (lc.length != 1) {
$('head').append('<style type="text/css">'+css+'</style>');
lc = $('<span id="lesson_count" class="dashboard_bubble"></span>');
rc = $('<span id="review_count" class="dashboard_bubble"></span>');
$('.wanikani-app-nav > ul > li:contains("Lessons")').append(lc);
$('.wanikani-app-nav > ul > li:contains("Reviews")').append(rc);
if (settings.show_next_review === true)
$('.wanikani-app-nav > ul').append('<li><a href="https://www.wanikani.com/review" title="Go to reviews">Next Review<span id="next_review" class="dashboard_bubble"></span></a></li>');
}
lc.text(lessons);
rc.text(reviews);
if (lessons === 0)
lc.addClass('zero');
else
lc.removeClass('zero');
if (reviews === 0)
rc.addClass('zero');
else
rc.removeClass('zero');
if (settings.show_next_review === true)
update_time();
}
//-------------------------------------------------------------------
// Fetch lesson/review count info from the server.
//-------------------------------------------------------------------
function fetch_data() {
var now = Math.round(new Date().getTime()/1000);
window.wkf_global.query_api('/study-queue')
.then(function(json){
var lessons = json.requested_information.lessons_available;
var reviews = json.requested_information.reviews_available;
next_review = json.requested_information.next_review_date;
update_counts(lessons, reviews);
}, function(error) {
alert('[Userscript - Wanikani Forum Lesson/Review Status]:\n\nWanikani is telling me, "'+error.message+'"\nMaybe check your API key?\nI\'ll take you to the settings page...');
window.wkf_global.goto_settings(error.message);
return;
});
var next_query = Math.trunc((now/900)+1) * 900 + Math.round(Math.random()*randomize_query) + 10 - now;
setTimeout(fetch_data, next_query*1000);
}
//-------------------------------------------------------------------
// Startup. Runs at document 'load' event.
//-------------------------------------------------------------------
function startup() {
// Attach the Dashboard menu to the stay-on-top menu.
var wk_app_nav = $('.wanikani-app-nav').closest('.container');
var top_menu = $('.d-header');
var main_content = $('#main-outlet');
$('body').addClass('float_wkappnav');
wk_app_nav.addClass('wanikani-app-nav-container');
top_menu.find('>.wrap > .contents:eq(0)').after(wk_app_nav);
// Adjust the main content's top padding, so it won't be hidden under the new taller top menu.
var main_content_toppad = Number(main_content.css('padding-top').match(/[0-9]*/)[0]);
main_content.css('padding-top', (main_content_toppad + 25) + 'px');
var now = Math.trunc(new Date().getTime()/1000);
var last_qtr_hr = Math.trunc(now / 900) * 900;
var last_query = Number(localStorage.getItem('wkf_lrstatus.last_query'));
fetch_data();
}
// Run startup() after window.onload event.
if (document.readyState === 'complete')
startup();
else
window.addEventListener("load", startup, false);
})(window.wkf_lrstatus);