Greasy Fork is available in English.

MaruMori Font Changer with Webfonts

Randomly change font of vocabulary or kani review items on marumori.io, including webfonts found under the SIL Open Font License. Font change reverts on hover.

// ==UserScript==
// @name         MaruMori Font Changer with Webfonts
// @namespace    http://tampermonkey.net/
// @version      0.4
// @description  Randomly change font of vocabulary or kani review items on marumori.io, including webfonts found under the SIL Open Font License. Font change reverts on hover.
// @author       You
// @match        https://marumori.io/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=marumori.io
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    console.log('Marumori Font Changer script has started.');

    // Local fonts (installed on your system)
    const localFonts = [
        'MS Gothic',
        'MS Mincho',
        'Meiryo',
        'Yu Gothic',
        'Yu Mincho',
        'Hiragino Kaku Gothic Pro',
        'Hiragino Mincho Pro',
        'Osaka',
        'TakaoGothic',
        'TakaoMincho',
        'Kochi Gothic',
        'Kochi Mincho'
    ];

    // Webfonts available on Google Fonts
    const webFonts = [
        'Noto Sans JP',
        'Noto Serif JP',
        'Sawarabi Gothic',
        'Sawarabi Mincho',
        'M PLUS Rounded 1c',
        'M PLUS 1p',
        'Kosugi',
        'Kosugi Maru',
        'Shippori Mincho',
        'Yuji Syuku',
        'Yuji Mai',
        'Yuji Boku',
        'Reggae One',
        'RocknRoll One',
        'Zen Kurenaido',
        'Zen Antique',
        'Zen Antique Soft',
        'Zen Maru Gothic',
        'Zen Kaku Gothic New',
        'Zen Old Mincho'
    ];

    // Combine both arrays for font selection
    const fonts = [...localFonts, ...webFonts];

    // Variable to store the previous item text
    let previousItemText = null;

    // Functions to get and set the locked font using GM_setValue and GM_getValue
    function setLockedFont(font) {
        GM_setValue('lockedFont', font);
        console.log('Locked font set to:', font);
    }

    function getLockedFont() {
        const font = GM_getValue('lockedFont', null);
        console.log('Retrieved locked font:', font);
        return font;
    }

    function getRandomFont() {
        const font = fonts[Math.floor(Math.random() * fonts.length)];
        console.log('Selected random font:', font);
        return font;
    }

    function addGoogleFont(fontName) {
        if (webFonts.includes(fontName)) {
            const linkId = 'google-font-' + fontName.replace(/\s+/g, '-');
            if (!document.getElementById(linkId)) {
                const link = document.createElement('link');
                link.id = linkId;
                link.href = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(fontName)}&display=swap`;
                link.rel = 'stylesheet';
                document.head.appendChild(link);
                console.log('Added Google Font link for:', fontName);
            }
        } else {
            console.log('Font is local, no need to add Google Font link:', fontName);
        }
    }

function showMessage(targetElement, message) {
    // Create message element
    const messageElement = document.createElement('div');
    messageElement.textContent = message;

    // Style the message element
    messageElement.style.position = 'absolute';
    messageElement.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
    messageElement.style.color = 'white';
    messageElement.style.padding = '5px 10px';
    messageElement.style.borderRadius = '5px';
    messageElement.style.fontSize = '12px';
    messageElement.style.zIndex = '1000';
    messageElement.style.pointerEvents = 'none'; // So it doesn't block clicks

    // Position the message element above the target element
    const rect = targetElement.getBoundingClientRect();
    messageElement.style.left = rect.left + window.pageXOffset + 'px';
    messageElement.style.top = rect.top + window.pageYOffset - 30 + 'px'; // Adjust as needed

    // Add to document
    document.body.appendChild(messageElement);

    // Remove after 1.5 seconds
    setTimeout(() => {
        document.body.removeChild(messageElement);
    }, 1500);
}

    function applyFontChange(targetElement) {
        // Store the original font family if not already stored
        if (!targetElement._originalFont) {
            targetElement._originalFont = window.getComputedStyle(targetElement).fontFamily;
            console.log('Original font:', targetElement._originalFont);
        }

        // Determine the font to use
        let lockedFont = getLockedFont();
        let newFont;
        if (lockedFont) {
            newFont = lockedFont;
            console.log('Using locked font:', newFont);
        } else {
            newFont = getRandomFont();
            console.log('Using new random font:', newFont);
        }

        // Store the new font on the target element
        targetElement._newFont = newFont;

        // Add the webfont if necessary
        addGoogleFont(newFont);

        // Apply the new font with !important
        targetElement.style.setProperty('font-family', `'${newFont}', sans-serif`, 'important');
        console.log('Applied font to target element:', newFont);

        // Remove existing event listeners to prevent duplicates
        targetElement.removeEventListener('mouseenter', targetElement._mouseenterHandler);
        targetElement.removeEventListener('mouseleave', targetElement._mouseleaveHandler);
        targetElement.removeEventListener('click', targetElement._clickHandler);

        // Define event handlers
        targetElement._mouseenterHandler = function() {
            this.style.setProperty('font-family', this._originalFont, 'important');
            console.log('Reverted to original font on hover:', this._originalFont);
        };

        targetElement._mouseleaveHandler = function() {
            // Reapply the same font after hover
            this.style.setProperty('font-family', `'${this._newFont}', sans-serif`, 'important');
            console.log('Reapplied font after hover:', this._newFont);
        };

targetElement._clickHandler = function(event) {
    if (event.shiftKey) {
        // Toggle font lock
        let lockedFont = getLockedFont();
        if (!lockedFont) {
            lockedFont = this._newFont;
            setLockedFont(lockedFont);
            console.log('Font locked:', lockedFont);
            showMessage(targetElement, 'Font Locked');
        } else {
            setLockedFont(null);
            console.log('Font unlocked');
            showMessage(targetElement, 'Font Unlocked');
        }
            } else {
                // Apply a new random font on click
                let newFont = getRandomFont();
                this._newFont = newFont;
                addGoogleFont(newFont);
                this.style.setProperty('font-family', `'${newFont}', sans-serif`, 'important');
                console.log('Applied new font on click:', newFont);

                let lockedFont = getLockedFont();
                if (lockedFont) {
                    // Update the locked font to the new font
                    setLockedFont(newFont);
                    console.log('Updated locked font to:', newFont);
                }
            }
        };

        // Attach event listeners
        targetElement.addEventListener('mouseenter', targetElement._mouseenterHandler);
        targetElement.addEventListener('mouseleave', targetElement._mouseleaveHandler);
        targetElement.addEventListener('click', targetElement._clickHandler);
    }

   function checkAndApply() {
    const targetElement = document.querySelector('#main .main_form, #main > span');
    if (targetElement) {
        console.log('Found target element:', targetElement);

        // Get the current item text
        const currentItemText = targetElement.textContent.trim();

        // Compare with the previous item text
        if (previousItemText !== currentItemText) {
            console.log('Item text has changed from', previousItemText, 'to', currentItemText);
            previousItemText = currentItemText;
            applyFontChange(targetElement);
        } else {
            console.log('Item text has not changed. No need to reapply font.');
        }
    } else {
        console.log('Target element not found.');
    }
}

    // Observe the body for changes
    const observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            // Call checkAndApply on any mutation
            checkAndApply();
        });
    });

    observer.observe(document.body, { childList: true, subtree: true });

    // Initial check
    checkAndApply();

})();