VNDB Card/Grid view buttons for producer page

Add buttons «Go to Card view» and «Go to Grid view» on https://vndb.org/PID pages.

// ==UserScript==
// @name         VNDB Card/Grid view buttons for producer page
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Add buttons «Go to Card view» and «Go to Grid view» on https://vndb.org/PID pages.
// @author       mleaqaavwv
// @match        https://vndb.org/p*
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';


    const suffixAlphabet = [
        ...Array.from({length: 10}, (_, i) => String(i)),
        ...Array.from({length: 26}, (_, i) => String.fromCharCode(97 + i)),
        ...Array.from({length: 26}, (_, i) => String.fromCharCode(65 + i)),
        '_', '-'
    ];

    function encodeNumber(n) {
        if (n <= 9) {
            return String(n);
        }
        if (n <= 35) {
            return String.fromCharCode(97 + (n - 10));
        }
        if (n <= 48) {
            return String.fromCharCode(65 + (n - 36));
        }

        let offset = n - 49;
        const base = suffixAlphabet.length; // 64


        const block1 = 10 * base;
        if (offset < block1) {
            const prefix = String.fromCharCode(78 + Math.floor(offset / base)); // 'N' → 78
            return prefix + suffixAlphabet[offset % base];
        }

        offset -= block1;


        const block2 = base * base;
        if (offset < block2) {
            const d1 = Math.floor(offset / base);
            const d2 = offset % base;
            return 'X' + suffixAlphabet[d1] + suffixAlphabet[d2];
        }

        offset -= block2;


        const d1 = Math.floor(offset / (base * base));
        const d2 = Math.floor(offset / base) % base;
        const d3 = offset % base;
        return 'Y' + suffixAlphabet[d1] + suffixAlphabet[d2] + suffixAlphabet[d3];
    }


    const match = window.location.pathname.match(/^\/p(\d+)/);
    if (!match) return;
    const vnId = parseInt(match[1], 10);
    const enc = encodeNumber(vnId);


    const cardUrl = `https://vndb.org/v?f=12N18N6830${enc}N6830${enc}&s=221`;
    const gridUrl = `https://vndb.org/v?f=12N18N6830${enc}N6830${enc}&p=1&s=222`;


    const container = document.createElement('div');
    Object.assign(container.style, {
        position: 'fixed',
        top: '10px',
        right: '10px',
        display: 'flex',
        flexDirection: 'column',
        gap: '5px',
        zIndex: '9999'
    });


    function makeButton(label, href) {
        const btn = document.createElement('a');
        btn.textContent = label;
        btn.href = href;
        btn.style.cssText = `
            display: inline-block;
            padding: 6px 12px;
            background: #4CAF50;
            color: #fff;
            border-radius: 4px;
            text-decoration: none;
            font-weight: bold;
            font-size: 0.9em;
            text-align: center;
        `;

        btn.addEventListener('mouseover', function() {
            btn.style.background = '#45A049';
        });
        btn.addEventListener('mouseout', function() {
            btn.style.background = '#4CAF50';
        });
        return btn;
    }

    container.appendChild(makeButton('Go to Card view', cardUrl));
    container.appendChild(makeButton('Go to Grid view', gridUrl));

    document.body.appendChild(container);
})();