Kumirei's Userscripts

By this I assume that the script actually did somthing when you wrote the command, right?

1 Like

Yes, it converted the input text into an icon, but no icon and didn’t save it to the list

1 Like

Ok. Let’s try some logging. Replace your script with this (and refresh the page!)

Code
// ==UserScript==
// @name         Wanikani Forums: Emoter
// @namespace    http://tampermonkey.net/
// @version      1.1.7
// @description  Custom emote handler
// @author       Kumirei
// @include      https://community.wanikani.com/*
// @grant        none
// ==/UserScript==

;(function () {
    // Wait until the save function is defined
    const i = setInterval(tryInject, 100)

    // Inject if the save function is defined
    function tryInject() {
        const old_save = window.require('discourse/controllers/composer').default.prototype.save
        const old_cook = window.require('pretty-text/engines/discourse-markdown-it').cook
        if (old_save) {
            clearInterval(i)
            inject(old_save, old_cook)
        }
    }

    // Wrap the save function with our own function
    function inject(old_save, old_cook) {
        const new_save = async function (t) {
            const composer = document.querySelector('textarea.d-editor-input') // Reply box
            composer.value = await emote(composer) // Modify message
            composer.dispatchEvent(new Event('change', { bubbles: true, cancelable: true })) // Let Discourse know
            old_save.call(this, t) // Call regular save function
        }
        const new_cook = async function (raw, ops) {
            return old_cook(emote_cooker(raw), ops)
        }
        window.require('discourse/controllers/composer').default.prototype.save = new_save // Inject
        window.require('pretty-text/engines/discourse-markdown-it').cook = new_cook // Inject
    }

    // Handles emotifications when saving
    function emote(composer) {
        const cache = get_local()
        const original_text = composer.value
        // Get draft text, without quotes
        // let text = original_text.replace(/\[quote((?!\[\/quote\]).)*\[\/quote\]/gis, '')
        // Replace stuffs?!
        text = replace_stuffs(original_text, cache)
        return text
    }

    // Change the preview
    function emote_cooker(raw) {
        const cache = get_local()
        const command_template = /!emote\s+(\w+)\s+(\w+)\s+(["“„](\S+)["”])?/i
        const composer = document.querySelector('textarea.d-editor-input') // Reply box
        const command = composer.value.match(command_template)
        // Do things if commands are present
        if (command) process_command(command, composer, command_template, cache)
        // Replace stuffs?!
        raw = replace_stuffs(raw, cache)
        // Update cache
        set_local(cache)
        console.log('Test 2:', localStorage.getItem('Emoter'));
        return raw
    }

    // Handles commands
    function process_command(command, composer, command_template, cache) {
        const emotes = cache.emotes
        let [_, word, name, __, value] = command
        word = word.toLowerCase()
        switch (word) {
            case 'new': // :NAME:
                if (value) emotes[name] = { url: value }
                console.log('Test 1:', name, emotes[name], value);
                break
            case 'size': // :NAME:
                if (value && !value.match(/\d+(x\d+)?/i)) break
                if (name === 'default') cache.size = value
            case 'url': // :NAME:
                if (value && emotes[name]) emotes[name][word] = value
                break
            case 'remove': // :NAME:delete emotes[name]
                break
            case 'rename': // :NAME:
                if (value && emotes[name]) delete Object.assign(emotes, { [value]: emotes[name] })[name]
                break
        }
        if (value || word === 'remove') {
            composer.value = composer.value.replace(command_template, ':$2:')
            composer.dispatchEvent(new Event('change', { bubbles: true, cancelable: true })) // Let Discourse know
        }
    }

    // Creates an image for the emote
    function get_image(url, name, size) {
        let w = (h = size)
        if (size.match && size.match(/\d+x\d+/i)) [w, h] = size.split('x')
        return `<abbr title="${name}">![${name}|${w}x${h}](${url})</abbr>`
    }

    // Replaces :emotes: with images and Image|Name
-|-
<abbr title="think">![think\|40x40](upload://nFUkGCE3POohnof4aw1OW0kQBWg.png)</abbr>|think
<abbr title="shocked">![shocked\|40x40](upload://lJcQ9GJpUbDPRdruUZRV5kW3Xgg.png)</abbr>|shocked
<abbr title="lain">![lain\|40x40](upload://vtUL7qltkfuQCwHDRuhF6E2E7iY.png)</abbr>|lain
<abbr title="winko">![winko\|40x40](upload://kbiFWSHsOYdoV95AU61ihpGVu7Q.png)</abbr>|winko
<abbr title="akkowoah">![akkowoah\|40x40](upload://nAERNMMxYpclkQaCTZ074wi0SYb.gif)</abbr>|akkowoah
<abbr title="eyes2">![eyes2\|20x20](upload://zKoTABayzXZmVJUw0YC79RGUF41.png)</abbr>|eyes2
<abbr title="arage">![arage\|40x40](upload://30LiRSxk2z8B3kZVbfV1wLpuYJJ.gif)</abbr>|arage
<abbr title="neat">![neat\|100x100](upload://7JaFvqTPXCNJPc1Aaf23wsM6uUD.gif)</abbr>|neat
<abbr title="akko">![akko\|40x40](upload://gDmQY7rnY0ef2T5VzshlyBRYiJW.png)</abbr>|akko
<abbr title="B">![B\|40x40](upload://5MFHeCFqx1uGznXXKNfDyQGgUoJ.png)</abbr>|B
<abbr title="pout">![pout\|40x40](upload://qD4IiH54Iqe16PgmkUJxC2eaRES.png)</abbr>|pout
<abbr title="wave">![wave\|40x40](upload://bnWeWodGFAhVnUXdZZROEdr6MtM.png)</abbr>|wave
<abbr title="brofive">![brofive\|60x60](upload://dhOE2k1TzhjLLcvZDmtk6HuCYow.png)</abbr>|brofive
<abbr title="blobfive">![blobfive\|40x40](upload://ql42JfiSLsqeVtdxy1dvIlSNUy7.png)</abbr>|blobfive
<abbr title="yui">![yui\|40x40](upload://k4PY0gdQkmk0Mp8yniRGnPYwu1u.png)</abbr>|yui
<abbr title="kms">![kms\|50x50](upload://vFrbHbKszjsFgLiuBYgTVijGXAO.png)</abbr>|kms
<abbr title="kannakms">![kannakms\|40x40](upload://rnQsXvis3HKCq0F5fQscyHgbI9Z.png)</abbr>|kannakms
<abbr title="blobkms">![blobkms\|40x40](https://cdn.discordapp.com/emojis/702873163482136576.gif?v=1)</abbr>|blobkms
<abbr title="blobparty">![blobparty\|40x40](https://cdn.discordapp.com/emojis/548314796089671681.gif?v=1)</abbr>|blobparty
<abbr title="vegans1">![vegans1\|198x330](upload://pqZsQn9oiTqfKx3NXZchxGDoxxs.jpeg)</abbr>|vegans1
<abbr title="vegans2">![vegans2\|198x330](upload://mGFLF8pwj9pVBTm9iKIgg1hI0vm.jpeg)</abbr>|vegans2
<abbr title="hehe">![hehe\|40x40](upload://9jrmEnTrpGxJxFn248p0isTb4kt.png)</abbr>|hehe</table> with the list
    function replace_stuffs(text, cache) {
        text = replace_emotes(text, cache)
        text = replace_list(text, cache)
        return text
    }

    // Replaces :emotes: with images
    function replace_emotes(text, cache) {
        return text.replace(/:(\w+):/g, (original, word) => {
            const emote = cache.emotes[word]
            return emote ? get_image(emote.url, word, emote?.size || cache.size) : original
        })
    }

    // Create a table of the available emotes
    function replace_list(raw, cache) {
        const list = Object.entries(cache.emotes)
            .map((e) => get_image(e[1].url, e[0], e[1].size || cache.size).replace('|', `\\|`) + `|` + e[0])
            .join('\n')
        const table = `Image|Name\n-|-\n${list}</table>`
        return raw.replace(/Image|Name
-|-
<abbr title="think">![think\|40x40](upload://nFUkGCE3POohnof4aw1OW0kQBWg.png)</abbr>|think
<abbr title="shocked">![shocked\|40x40](upload://lJcQ9GJpUbDPRdruUZRV5kW3Xgg.png)</abbr>|shocked
<abbr title="lain">![lain\|40x40](upload://vtUL7qltkfuQCwHDRuhF6E2E7iY.png)</abbr>|lain
<abbr title="winko">![winko\|40x40](upload://kbiFWSHsOYdoV95AU61ihpGVu7Q.png)</abbr>|winko
<abbr title="akkowoah">![akkowoah\|40x40](upload://nAERNMMxYpclkQaCTZ074wi0SYb.gif)</abbr>|akkowoah
<abbr title="eyes2">![eyes2\|20x20](upload://zKoTABayzXZmVJUw0YC79RGUF41.png)</abbr>|eyes2
<abbr title="arage">![arage\|40x40](upload://30LiRSxk2z8B3kZVbfV1wLpuYJJ.gif)</abbr>|arage
<abbr title="neat">![neat\|100x100](upload://7JaFvqTPXCNJPc1Aaf23wsM6uUD.gif)</abbr>|neat
<abbr title="akko">![akko\|40x40](upload://gDmQY7rnY0ef2T5VzshlyBRYiJW.png)</abbr>|akko
<abbr title="B">![B\|40x40](upload://5MFHeCFqx1uGznXXKNfDyQGgUoJ.png)</abbr>|B
<abbr title="pout">![pout\|40x40](upload://qD4IiH54Iqe16PgmkUJxC2eaRES.png)</abbr>|pout
<abbr title="wave">![wave\|40x40](upload://bnWeWodGFAhVnUXdZZROEdr6MtM.png)</abbr>|wave
<abbr title="brofive">![brofive\|60x60](upload://dhOE2k1TzhjLLcvZDmtk6HuCYow.png)</abbr>|brofive
<abbr title="blobfive">![blobfive\|40x40](upload://ql42JfiSLsqeVtdxy1dvIlSNUy7.png)</abbr>|blobfive
<abbr title="yui">![yui\|40x40](upload://k4PY0gdQkmk0Mp8yniRGnPYwu1u.png)</abbr>|yui
<abbr title="kms">![kms\|50x50](upload://vFrbHbKszjsFgLiuBYgTVijGXAO.png)</abbr>|kms
<abbr title="kannakms">![kannakms\|40x40](upload://rnQsXvis3HKCq0F5fQscyHgbI9Z.png)</abbr>|kannakms
<abbr title="blobkms">![blobkms\|40x40](https://cdn.discordapp.com/emojis/702873163482136576.gif?v=1)</abbr>|blobkms
<abbr title="blobparty">![blobparty\|40x40](https://cdn.discordapp.com/emojis/548314796089671681.gif?v=1)</abbr>|blobparty
<abbr title="vegans1">![vegans1\|198x330](upload://pqZsQn9oiTqfKx3NXZchxGDoxxs.jpeg)</abbr>|vegans1
<abbr title="vegans2">![vegans2\|198x330](upload://mGFLF8pwj9pVBTm9iKIgg1hI0vm.jpeg)</abbr>|vegans2
<abbr title="hehe">![hehe\|40x40](upload://9jrmEnTrpGxJxFn248p0isTb4kt.png)</abbr>|hehe</table>/i, table)
    }

    // Fetch local storage cache
    function get_local() {
        const cache = JSON.parse(localStorage.getItem('Emoter') || '{}')
        return Object.assign({ size: 40, emotes: {} }, cache)
    }

    // Saves to local storage
    function set_local(cache) {
        localStorage.setItem('Emoter', JSON.stringify(cache))
    }
})()

Then go to the console tab and make sure to show all messages

image

Then add an emote, and take a screenshot of the logs

Could you possibly have more than one instance of the script running?

Can we include mine (details over at WaniKani Discord Bot (Unaffiliated)) after we begin releasing versions?

This is just a list of the scripts that I made. I think you are looking for this list

You should be able to add to it yourself, once you are ready

2 Likes

!emote url tj3starsing “https://i.imgur.com/NfvOTBy.png

Sorry for only just now trying this, but I still can’t get it to work ):

I’m having trouble with the !emote script no longer displaying my emotes. :cry:

I’ve had increasing issues these past days and today Firefox upgraded to a new version that changes stuff around more than usual. I’ve had all scrips reset to default 3 times in 3 days, but hoped that would be the end of it. I couldn’t log on today without deleting my wanikani cookies. (rip my regular counter status)

But this latest bout of problems just puzzles me…what’s going on here??

testing :high_touch:

  • testing :high_touch:

0 voters

not to mention my durtle emoticons don’t work it seems.

Sorry if the break off point doesn’t check out but I just wanted to catch the last messages on my console

What do I need to do to fix the emoticons? :eyes:

1 Like

I’m sorry, what are you testing in your post?

Also, if you deleted your cache your saved emotes are also gone

2 Likes

!emote new tj3starexcite “https://i.imgur.com/0oDOQrn.png”
!emote new tj3starlaser “https://i.imgur.com/siAA26a.png”

1 Like

You can’t even add new ones though

I see…rip T_T

2 Likes

I don’t know which topic should I ask. So my best bet should be here.

Is there any script that prevent me from entering Wanikani community webboard if I still not finish all the review?

That would be the best motivation to finish all the review lol

1 Like

Can we get an Other Voice Actor update plz. It broke. I got used to pressing I but now no Kyoko :cry:

1 Like

Try Procrastination Annihilation and Remove useless panels

2 Likes

Of course! I’ll look into it next week!

3 Likes

This should be fixed now!

Omg thanks :tada: but I found bugs…
I did my reviews and it was fine except one thing, I got “tomorrow” and answered あす but Kyoko said みょうにち (I don’t remember how previous version of script behaved when multiple answers) I expected her to say あす too, or first item あした .
Then I decided to check if lessons worked, get whichever lvl16 vocab but Kyoko says しょうひん from latest review item 商品. Page refresh not helping, script reinstall not helping. Fix pls? :pleading_face:

1 Like

Does this work? Can I just copy paste this and update the greasyfork script?

1 Like

Yep, it works! Got help from this post over there.

I’m surprised you found my post :eyes:

1 Like