您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Changes the count of lessons on the Today's Lessons tile to show the total number of available lessons in addition to the number selected for you
当前为
// ==UserScript== // @name Show Total Lesson Count - WaniKani // @namespace http://tampermonkey.net/ // @version 0.5.2 // @description Changes the count of lessons on the Today's Lessons tile to show the total number of available lessons in addition to the number selected for you // @license MIT // @author LupoMikti // @match https://www.wanikani.com/* // @grant none // @supportURL https://community.wanikani.com/t/userscript-show-total-lesson-count/66776 // ==/UserScript== (async function() { 'use strict'; /* global wkof */ let scriptId = 'show_total_lesson_count'; let scriptName = 'Show Total Lesson Count'; let initial_load = true; let todaysLessonsCount; let settings; let stateStarting = false; let todaysLessonsFrameLoaded = false; let navBarCountFrameLoaded = false; let debugLogText = `START: ${scriptName} Debug Log:\n`; let hasOutputLog = false; let mainSource = ''; const INTERNAL_DEBUG_TURBO_HANDLING = false; function addToDebugLog(message) { debugLogText += `${new Date().toISOString()}: ${message}\n`; } function printDebugLog(force = false) { if (!hasOutputLog || force) { console.log(`${scriptName}: Outputting a debug log to console.debug()`); console.debug(debugLogText); } if (!force) hasOutputLog = true; debugLogText = `START: ${scriptName} Debug Log:\n`; } if (!window.wkof) { if (confirm(scriptName + ' 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; } const wkofTurboEventsScriptUrl = 'https://update.gf.qytechs.cn/scripts/501980/1423213/Wanikani%20Open%20Framework%20Turbo%20Events.user.js'; addToDebugLog(`Attempting to load the TurboEvents library script...`) await wkof.load_script(wkofTurboEventsScriptUrl, /* use_cache */ true); addToDebugLog(`Checking if TurboEvents library script is loaded in...`) let injectedDependency = document.head.querySelector('script[uid*="Turbo"]'); addToDebugLog(`Turbo Events library ${injectedDependency ? 'is' : 'is NOT' } loaded.`); if (INTERNAL_DEBUG_TURBO_HANDLING) { window.addEventListener('turbo:load', () => { console.log(`DEBUG: turbo:load has fired`); }); window.addEventListener('turbo:before-frame-render', (e) => { console.log(`DEBUG: turbo:before-frame-render has fired for '#${e.target.id}'`); }); window.addEventListener('turbo:frame-load', (e) => { console.log(`DEBUG: turbo:frame-load has fired for '#${e.target.id}'`); }); } const _init = (source) => { if (stateStarting) { addToDebugLog(`We are already in the starting state, no need to initialize, returning...`); return; } addToDebugLog(`SOURCE = "${source}" | Setting globals and calling _start()`); initial_load = stateStarting = true; hasOutputLog = todaysLessonsFrameLoaded = navBarCountFrameLoaded = false; _start(); }; wkof.ready('TurboEvents').then(() => { addToDebugLog(`Start of TurboEvents ready callback`) let urlList = [wkof.turbo.common.locations.dashboard, wkof.turbo.common.locations.items_pages, /^https:\/\/www\.wanikani\.com\/(settings|level|radicals|kanji|vocabulary)(\/|\?difficulty=).+\/?$/]; wkof.turbo.on.event.load((e) => { _init('turbo:load'); }, { urls: urlList }); wkof.turbo.on.event.before_frame_render((e) => { const frameId = e.target.id; if (initial_load && !stateStarting) { addToDebugLog(`initial_load is true (no frames were previously retrieved) and we are not already in starting state, starting initialization sequence...`); _init('turbo:before-frame-render'); } if (frameId === 'todays-lessons-frame') { addToDebugLog(`turbo:before-frame-render has fired for "#${frameId}"`); todaysLessonsFrameLoaded = false; } else if (frameId === 'lesson-and-review-count-frame') { addToDebugLog(`turbo:before-frame-render has fired for "#${frameId}"`); navBarCountFrameLoaded = false; } else { addToDebugLog(`turbo:before-frame-render was fired for "#${frameId}", doing nothing...`); } }, { urls: urlList }); wkof.turbo.on.event.frame_load(async (e) => { const frameId = e.target.id; if (frameId === 'todays-lessons-frame') { addToDebugLog(`turbo:frame-load was fired for "#${frameId}, calling main function"`); todaysLessonsFrameLoaded = true; mainSource = `turbo:frame-load for "#${frameId}"`; await main(); } else if (frameId === 'lesson-and-review-count-frame') { addToDebugLog(`turbo:frame-load was fired for "#${frameId}, calling main function"`); navBarCountFrameLoaded = true; mainSource = `turbo:frame-load for "#${frameId}"`; await main(); } else { addToDebugLog(`turbo:frame-load was fired for "#${frameId}", doing nothing...`); } mainSource = ''; }, { urls: urlList }); addToDebugLog(`All turbo callbacks have been sent to TurboEvents library to be registered`); }).catch((err) => { addToDebugLog(`TurboEvents library rejected with error: ${err}`); }) .finally(() => { if (INTERNAL_DEBUG_TURBO_HANDLING) { addToDebugLog(`SOURCE: turbo ready finally`); printDebugLog(INTERNAL_DEBUG_TURBO_HANDLING); } }); function _start() { addToDebugLog(`Starting...`); wkof.include('Settings, Menu, Apiv2'); wkof.ready('Settings, Menu, Apiv2').then(loadSettings).then(insertMenu).then(main) .catch((err) => { addToDebugLog(`wkof.ready() rejected with error: ${err}`); }) .finally(() => { if (INTERNAL_DEBUG_TURBO_HANDLING) { addToDebugLog(`SOURCE: wkof modules ready finally`); printDebugLog(INTERNAL_DEBUG_TURBO_HANDLING); } }); } function loadSettings() { addToDebugLog(`Loading settings...`); let defaults = { showTotalOnly: false, setOwnPreferredDaily: false, preferredDailyAmount: wkof.user.preferences.lessons_batch_size * 3, enableDebugging: true, }; return wkof.Settings.load(scriptId, defaults).then(function(wkof_settings) {settings = wkof_settings;}); } function insertMenu() { addToDebugLog(`Inserting menu...`); let config = { name: scriptId, submenu: 'Settings', title: scriptName, on_click: openSettings }; wkof.Menu.insert_script_link(config); mainSource = `_start() -> loadSettings() -> insertMenu()`; } async function saveSettings(wkof_settings) { hasOutputLog = false; addToDebugLog(`Save button was clicked on settings, calling main() with new settings...`); mainSource = 'wkof.Settings.save()'; settings = wkof_settings; await main(); } function openSettings() { let config = { script_id: scriptId, title: scriptName, on_save: saveSettings, content: { showTotalOnly: { type: 'checkbox', label: 'Show Only Total Lesson Count', hover_tip: `Changes display between "<today's lesson count> / <total lesson count>" and just "<total lesson count>"`, default: false, }, setOwnPreferredDaily: { type: 'checkbox', label: '(DEPRECATED 1)', hover_tip: `THIS SETTING HAS BEEN DEPRECATED DUE TO THE OFFICIAL SETTING FROM WANIKANI.`, default: false, }, preferredDailyAmount: { type: 'number', label: '(DEPRECATED 2)', hover_tip: `THIS SETTING HAS BEEN DEPRECATED DUE TO THE OFFICIAL SETTING FROM WANIKANI.`, min: 0, max: 100, }, enableDebugging: { type: 'checkbox', label: 'Enable console debugging', hover_tip: `Enable output of debugging info to console.debug()`, default: true, } } }; let dialog = new wkof.Settings(config); dialog.open(); } function getCountContainers() { let dashboardTileCountContainer = document.querySelector('.todays-lessons__count-text .count-bubble'); let navBarCountContainer = document.querySelector('.lesson-and-review-count__count'); if (initial_load && (dashboardTileCountContainer || navBarCountContainer)) { let container = dashboardTileCountContainer ?? navBarCountContainer; todaysLessonsCount = parseInt(container.textContent); initial_load = false; } return [dashboardTileCountContainer, navBarCountContainer]; } async function main() { addToDebugLog(`Main function is executing... source of start = ${mainSource}`); if (!settings) { addToDebugLog(`We do not have settings, setting timeout on _start()`); if (!stateStarting) { setTimeout(_start, 50); } else addToDebugLog(`Did not set timeout due to already being in starting state`); addToDebugLog(`Main function has finished executing`); return; } addToDebugLog(`We have settings`); addToDebugLog(`Retrieving summary data via await of the enpoint...`); let summary_data = await wkof.Apiv2.get_endpoint('summary'); addToDebugLog(`Summary data has been retrieved`); let totalLessonCount = summary_data.lessons[0].subject_ids.length; let lessonCountContainers; if (todaysLessonsFrameLoaded || navBarCountFrameLoaded) { addToDebugLog(`Frame(s) loaded, retrieving containers in frames containing the counts...`); lessonCountContainers = getCountContainers(); addToDebugLog(`Count containers have been retrieved`); } else { addToDebugLog(`No frames loaded`); addToDebugLog(`Main function has finished executing`); //if (settings.enableDebugging) printDebugLog(INTERNAL_DEBUG_TURBO_HANDLING); return; } let todaysCountForDisplay = todaysLessonsCount; if (lessonCountContainers.every(node => node == null)) { addToDebugLog(`No nodes in containers`); addToDebugLog(`Main function has finished executing`); //if (settings.enableDebugging) printDebugLog(INTERNAL_DEBUG_TURBO_HANDLING); return; } addToDebugLog(`At least one container exists`); stateStarting = false; if (isNaN(todaysLessonsCount)) todaysCountForDisplay = 0; if (lessonCountContainers[0]) { lessonCountContainers[0].textContent = settings.showTotalOnly ? totalLessonCount : todaysCountForDisplay + ' / ' + totalLessonCount; addToDebugLog(`Setting display amount for Today's Lessons tile, set to ${lessonCountContainers[0].textContent}`); } if (lessonCountContainers[1]) { lessonCountContainers[1].textContent = settings.showTotalOnly ? totalLessonCount : todaysCountForDisplay; addToDebugLog(`Setting display amount for navigation bar, set to ${lessonCountContainers[1].textContent}`); } if (todaysCountForDisplay === 0) { addToDebugLog(`Hiding start button due to having 0 lessons with configured count source`); // hide the start button if it is not already, TODO: disable nav bar button if it is not already let startButton = document.querySelector('.todays-lessons-button--start') if (startButton && startButton.checkVisibility()) { startButton.style.display = 'none'; } } // hide "Today's" subtitle let lessonSubtitle = document.querySelector('.todays-lessons__subtitle'); if (lessonSubtitle && lessonSubtitle.checkVisibility()) { addToDebugLog(`Hiding the "Today's" subtitle on the lesson tile`); lessonSubtitle.style.display = 'none'; } addToDebugLog(`Main function has successfully executed`); if (settings.enableDebugging) printDebugLog(INTERNAL_DEBUG_TURBO_HANDLING); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址