[Userscript] Back To Back

Maybe it’s just me. However, I can’t find the option to adjust the settings of this script under “user icon → scripts → settings”. Where should I be looking?

1 Like

The script is only active during a session, so you’ll have to access the settings during a review or a lesson session

1 Like

Thank you! I happened to stumble across it on my own, when I finally got curious about that “cog” I’ve seen during the reviews that I’ve never clicked before, haha.

1 Like

Where are the settings stored? Mine get lost when I close the browser. I use a bunch of extensions so I am pretty sure one of those is the culprit. I tried whitelisting wanikani.com in CookieAutoDelete but that didn’t help. So could you please let me know where and/or how the settings are stored?
Thank you very much for a very useful script!

1 Like

All scripts that use WKOF have their settings stored in IndexedDB, which is separate from cookies and localStorage, but will still be cleared whenever cache is cleared

Thank you!

Moving here to keep some semblance of organization. Maybe there’s a way to not use the random hack. I’ve looked at the code and maybe monkey patching window.sessionStorage.get to
a) return only 1 item when the active queue is requested
b) return {mc: 1} and {rc: 1} respectively for the stats to force it to do the exact type we want
could work. It’s an entirely different hack.

2 Likes

Yes, I‘d also be happy if the script could do without overwriting the random function. Firstly because I think it’s super hacky (but that’s just my developer brain talking so you can ignore that) and secondly because the script obviously doesn’t randomize any more! For the reviews that doesn’t matter as much but for the lesson quiz it gets extremely boring as I can often remember the items in order so I need not recall the actual kanji but just need to come up with what I learned, in order.

So I had a go at the script but did not really succeed, unfortunately. My idea was to change it to something like this:

    function findNextItem(prio) {
        const allItems = $.jStorage.get("activeQueue");
        const nextItem = allItems.find(item => {
            const done = $.jStorage.get(uidFor(item));
            return done && !done[prio === 'reading' ? 'mc' : 'rc'];
        })
        // return the item that was reviewed but is at least missing the non-prioritized review (while the prioritized may be correct or wrong),
        // or else use the next one in line
        return nextItem || $.jStorage.get(currentItemKey);
    }

    // Prioritize reading or meaning
    function prioritize() {
        const prio = wkof.settings[script_id].prioritize;
        if('none' === prio) return;

        const item = findNextItem(prio);
        // Skip if item is a radical
        if (item.type === 'Radical') return;

        // change the item in any case because we don't know which one we picked
        $.jStorage.set(currentItemKey, item);

        const done = $.jStorage.get(uidFor(item));
        if (!done || !done[prio === 'reading' ? 'rc' : 'mc']) {
            // Change the question type to the priority if no question has been answered yet,
            // or the priority question has not been answered correctly yet
            $.jStorage.set(questionTypeKey, prio);
        } else {
            // Change to non-priority otherwise (because the item may have changed)
            $.jStorage.set(questionTypeKey, prio === 'reading' ? 'meaning' : 'reading');
        }
    }

where at first you would check the queue to see whether there is an unfinished item left in it (the queue always seems to be quite short, so this should be quick to search even for large reviews). If it is, then pick that one, otherwise just go with the first item and switch it to the prioritized side if needed. This way you can probably remove all of the random() overwriting and the other initialization stuff you’re doing.

But unfortunately, it doesn’t work! It seems that the script is invoked multiple times? (When I add a log message to the function, it gets invoked several times, which I did not expect.) Sometimes it bails out with “too many recursions” which also surprises me since I’m not adding recursion, just a non-recursive function call. And finally, it’s pretty slow, which also confuses me (the browser is definitely capable of handling much more than that little bit of searching around that I’m doing in there).

So maybe my draft gives you some ideas on how to improve the script - and if not, feel free to ignore :slight_smile:

1 Like

Are you doing this in a listenOnKeyChange? Because then you are in fact recursing when you set the current item.

There will need to be a hack somewhere, that’s why this is a userscript. I quite like the fact that the script makes the random function throw and then tries to figure out where that was. Metal as hell.

1 Like

I’m doing this in the same place as the original script. :woman_shrugging:

Not really sure about that, but I’m ok to disagree with you on that one - no need to fight :wink:

1 Like

How about wrapping jStorage.set() and changing the item being set when setting currentItem? Actually, that would work with the Back To Back feature of Omega, as presumably no other script would need to set the current item if you use Omega, but that wouldn’t be viable for this standalone script.

Preferably there would be a less hacky way to do it that preserves the ability to change the current item

edit: I didn’t check lessons, but at least for reviews wrapping Math.floor() is also an option, and combined with checking the trace it might be less disruptive for other scripts

WK’s review code:

randomQuestion(postSubmitCompleteCallback) {
    const list = $.jStorage.get("activeQueue");
    const item = list[Math.floor(Math.random() * list.length)];

Oh! I just saw this and realized that I could just look for the extra argument that WK sends jStorage.set(). That would make wrapping .set() pretty good

    const currentItem = $.jStorage.set("currentItem", item, {
      source: "reviews/random",
    });
1 Like

And if you check for questionType too and change that as well, I think you should be entirely done with the functionality

1 Like

Looks like they don’t do the same for lessons, so we don’t have a satisfactory solution for lessons

There should be a faker script made for lessons, because I don’t have any and can’t test

1 Like

I switch to a test account when I want to try anything with lessons. This is the function that WK uses to select the next item in lesson quiz, though. I think the best option might be to switch to wrapping jStorage.set() for reviews, and maybe Math.floor() (and check error trace) for lessons?

  selectItem() {
    const activeQueue = $.jStorage.get("l/activeQueue");
    const item = activeQueue[Math.floor(Math.random() * activeQueue.length)];
    const itemStat = getStats(item, "lesson");
    const itemType = getItemType(item);
    let questionType;
    if (itemType === "radical") {
      questionType = "meaning";
    } else {
      const noStats =
        itemStat === null ||
        (typeof itemStat.mc === "undefined" &&
          typeof itemStat.rc === "undefined");
      if (noStats) {
        questionType = ["meaning", "reading"][Math.floor(Math.random() * 2)];
      } else {
        if (itemStat.mc >= 1) {
          questionType = "reading";
        }
        if (itemStat.rc >= 1) {
          questionType = "meaning";
        }
      }
    }
    $.jStorage.set("l/questionType", questionType);
    $.jStorage.set("l/currentQuizItem", item);
    renderForm("lesson");
  },

Why can’t the set wrapping option be used for this though? Doesn’t it do a very similar thing? Set the current item, the current item type and then render it?

1 Like

Without any way to discriminate between WK calling the function and other scripts calling the function you would completely remove the functionality of setting the current item. A reordering script, for example, could change the active queue, but would not be able to pick which item comes first.

Actually, you’re right. As long as the script only changes the item when one question has been answered already it shouldn’t be an issue. Only doing it when WK is setting the item is a nice bonus for reviews, though

1 Like

That’s what I’m doing in the code snippet I posted above :slight_smile: Good that we agree on that. This way you can keep the randomization.

1 Like

@Gorbit99 @NicoleIsEnough I have updated this script as well as Omega to use the .set() hack instead

2 Likes

That looks very good to me (code-wise), thank you! Will try it out tomorrow morning when I do my next lessons.

I think you can now remove the Math.random warning in line 55 ff. :wink:

1 Like