[Unsupported] [Userscript] WaniKani Review Audio Tweak (reupload/fixed)

Thanks for the tip! Update complete. I still can’t get it to do exactly what I want, tho. See note in userscript code if interested.
https://greasyfork.org/en/scripts/377361-wanikani-review-audio-tweak-3

The problem is that you’re using let in the commented out code. let is used for defining new variables, but the variable was already passed in to the function. So you want to just assign it without the let, like this:

if (questionType === "meaning") {
	audioAutoplay = false;
}

Slightly more technical explanation

To go into slightly more detail, the code before was using var to declare variables. var is the old version of assigning variables in JavaScript, and does this quirky thing called “hoisting” (which you can look up if you’re interested). let on the other hand follows an approach more similar to most programming languages, called block scoping. What that means is, a variable declared within a block (e.g. function, loop, condition) using let will only exist within that block. So with your current code, you are actually creating a new variable called audioAutoplay within the if block (effectively hiding the one passed into the function) instead of actually overwriting the one passed into the function with a new value.

2 Likes

Sweet, my man seanblue is on the case.

Thanks for detailed heads-up! What you say about block scoping makes total sense. Actually, tho, this is sort of an unfortunate red herring; I only added the let (not knowing that it would result in a more restrictive scope) as a desperate flail after many other attempts. Even if the let is not there (I’ve updated again), it still doesn’t work as hoped.

Specifically, the problem seems to lie with the parameter audioAutoplay. On the one hand, it simply always comes in as false, regardless of the real setting. But even assuming that I manually override that to true, I don’t seem to be able to successfully use if statements to change it in response to other variables in order to then pass it in with the { autoplay } object so as to make it do something useful. I.e., total fail.

I’m a Python programmer, not at all skilled in Javascript, so I feel like I’m stabbing around in the dark here, not really understanding why things don’t behave as expected, nor how to get more information. If you want to point me toward where to learn more, I’d be grateful.

I debugged through my version and also always saw false passed in for audioAutoplay. But my version of the script seems to work. I didn’t originally build this script, so I never did a thorough debugging through WaniKani’s code to understand how all this works. Now I’m honestly confused too, and I’m not sure how this works at all. :sweat_smile:

There is also a global variable called audioAutoplay which is passed into this additionalContent.audio function we’re overriding, so maybe that’s relevant somehow. But if it is, I’m not sure why it would be false locally in additionalContent.audio since it’s true globally when the autoplay setting is on.

1 Like

Right, that’s exactly the confusion I have too, which makes me feel more sane. Well, so, if I don’t improve this particular script any further, that’s basically ok with me.

But more generally, do you actually know HOW to debug through WaniKani code? Where would you start? I know how to inspect page source, and I know vaguely of the developer console — and the Open Framework looks like a fun thing to work with — but it’s unclear to me how to build a general picture of how many moving parts there are and how they work together.

There’s a button in the Chrome console (Source tab) to de-minify the code once you’ve opened it, so it’s at least somewhat readable. Then I usually search for HTML classes/ids that could be used or things like $.jStorage.get, which is how they maintain state (as you can see in this script). It’s very trial and error. A good way to start is by looking through existing scripts, like this one and [Userscript] WaniKani Prioritize Overdue Reviews (NEW reorder script).

Ok, cool stuff, thanks so much for sharing. Every little tip helps.

@seanblue Unfortunately, your script seems to have issues with the new audio update. It still works but when it’s active, it plays either male or female audio to each vocabulary item, “ignoring” the new option in Wanikani settings to select only male or only female audio.

To clarify, the choice of male/female audio doesn’t seem random, as even when I kept reloading to test this, I always got the same audio (either male or female) for the same word. Similarly, even when I kept pressing the audio button/J hotkey, the audio never changed.

Sorry to bother you with this but do you think it would be possible to make your script compatible with Wanikani’s new feature of picking one’s preferred audio?

2 Likes

This is looking like it’ll be a pain to fix. The script was working by duplicating code from WaniKani but changing one condition (to allow for audio to play after meaning review when reading had already been answered correctly). But in the latest update they basically rewrote that code from scratch. So I’d have to dig through their code and duplicate it again, risking it breaking the next time they update audio. At the very least, I want to wait a few days until the updates in this area have stabilized, but it kind of rubs me the wrong way to duplicate their code at all (I didn’t originally write the script, just maintained it since an audio URL changed).

Maybe our friendly WaniKani developer @viet would consider this feature as a first-class citizen. :slight_smile:

3 Likes

You could add a check for preferred audio (although still without regard to which reading you entered) to work around this.

+				if (audio.voice_actor_id == WaniKani.default_voice_actor_id) {
					$('<source></source>', {
						src: audio.url,
						type: audio.content_type
					}).appendTo(audioElem);
+				}
2 Likes

Thanks! This looks promising but I don’t know where to add this check in the code :sweat_smile:

Just look for the line $('<source></source>', {. I only added the first and last of the lines in my previous post (indicated by the +)

1 Like

This fixed the problem! Thank you, I really appreciate your help.

1 Like

Thank you for the quick response! Digging through the code like that really sounds like a hassle, especially since future updates might break things again. :slightly_frowning_face:

For now, maybe you could add the quick fix Kumirei posted above to your script? Seems like it has fixed the problem for me.

I’ll test it out tomorrow and do that if it works.

1 Like

@Kumirei If you haven’t noticed any issues with your tweaked version can you post it here? Much appreciated!

The only issue I have had is that it sometimes picks the less common reading when an item has more than one reading. It surprises me when I enter the only reading I know and it plays a different reading. For me this is more of a feature, since I get familiar with other readings, but it could be considered a serious issue by some.

Either way, here’s the code. I believe I only added that check for the preferred VA, and the fix for multiple audio being played at the same time.

// ==UserScript==
// @name          WaniKani Review Audio Tweak 2
// @namespace     https://www.wanikani.com
// @description   Allow audio to be played after review meaning questions, when reading has been previously answered correctly. Also includes setting for enabling autoplay when answer is incorrect (default: off). Originally by Takuya Kobayashi.
// @author        seanblue
// @version       1.0.1
// @include       https://www.wanikani.com/review/session*
// @run-at        document-end
// @grant         none
// ==/UserScript==

// Original version by Takuya Kobayashi: https://greasyfork.org/en/scripts/10184-wanikani-review-audio-tweak
// This version is a reupload with the new URL for audio files.

(function ($) {
	'use strict';
	// BEGIN SETTINGS //
	const enableAutoPlayWhenIncorrect = true; // change to 'true' to enable
	// END SETTINGS //

	function itemStat(item) {
		let itemStatKey = (item.voc ? 'v' : item.kan ? 'k' : 'r') + item.id;
		return ($.jStorage.get(itemStatKey) || {});
	}

	window.additionalContent.audio = function (audioAutoplay) {
		let currentItem = $.jStorage.get('currentItem');
		let questionType = $.jStorage.get('questionType');

		$('audio').remove();

		if (currentItem.aud && (questionType === 'reading' || itemStat(currentItem).rc >= 1)) {
			let liElem = $('#option-audio');
			let buttonElem = liElem.find('button');

			if (!enableAutoPlayWhenIncorrect && !$('#answer-form fieldset').hasClass('correct')) {
				audioAutoplay = false;
			}

			buttonElem.removeAttr('disabled');
			let audioElem = $('<audio></audio>', { autoplay: audioAutoplay }).appendTo(liElem.removeClass('disabled').children('span'));

			for (let i = 0; i < currentItem.aud.length; i++) {
				let audio = currentItem.aud[i];

				if (audio.voice_actor_id == WaniKani.default_voice_actor_id) {
					$('<source></source>', {
						src: audio.url,
						type: audio.content_type
					}).appendTo(audioElem);
				}
			}

			audioElem[0].addEventListener('play', function () {
				buttonElem.removeClass('audio-idle').addClass('audio-play');
			});

			audioElem[0].addEventListener('ended', function () {
				buttonElem.removeClass('audio-play').addClass('audio-idle');
			});

			buttonElem.off('click');
			buttonElem.on('click', function () {
				audioElem[0].play();
			});

			liElem.off('click');
			liElem.on('click', function () {
				if ($('#user-response').is(':disabled')) {
					$('audio.preferred').trigger('play');
				}
			});
		}
	};
}(window.jQuery));
1 Like

I can’t get this script to work. I disabled all other scripts (except WK open framework) in case something was conflicting with it but that didn’t seem to make a difference.

Are there settings for this script because the icon I go to normally to adjust script settings during reviews doesn’t show any menu item for this script. Thanks in advance for any assistance!

This script is not integrated with WKOF and only has one setting in the script at the top of the code.

I don’t know why it wouldn’t work, as it works for me. What exactly is not working?

Nevermind, I really should spend more time tinkering with things before asking for help. Problem was related to audio hardware… this is why the first step of troubleshooting should be to ask if everything is plugged in lol.

2 Likes