Greasy Fork

Greasy Fork is available in English.

Platesmania Lookup Toolbox

Shows lookup buttons on Platesmania upload pages.

当前为 2025-09-21 提交的版本,查看 最新版本

// ==UserScript==
// @name         Platesmania Lookup Toolbox
// @version      1.8.0
// @description  Shows lookup buttons on Platesmania upload pages.
// @match        https://platesmania.com/*/add*
// @grant        GM_setValue
// @grant        GM_xmlhttpRequest
// @connect      opendata.rdw.nl
// @connect      motonet.fi
// @license      MIT
// @namespace    http://greasyfork.icu/users/976031
// ==/UserScript==

(function () {
    'use strict';

    const lookupSites = {
        nl: [
            { name: 'Finnik', base: 'https://finnik.nl/kenteken/' },
            { name: 'Autoweek', base: 'https://www.autoweek.nl/kentekencheck/' },
            { name: 'voertuig.net', base: 'https://voertuig.net/kenteken/' },
            { name: 'Centraal Beheer', base: 'https://centraalbeheer.finnik.nl/kenteken/' },
            { name: 'Kentekencheck.info', base: 'https://www.kentekencheck.info/kenteken/' },
            { name: 'Kentekencheck.nu', base: 'https://www.kentekencheck.nu/kenteken/' },
            { name: 'Qenteken', base: 'https://www.qenteken.nl/kentekencheck/' },
            { name: 'RDW (Website)', base: 'https://www.rdwdata.nl/kenteken/' },
        ],
        se: [
            { name: 'car.info', base: 'https://www.car.info/?s=' },
            { name: 'biluppgifter.se', base: 'https://biluppgifter.se/fordon/' },
            { name: 'transportstyrelsen', base: 'https://fordon-fu-regnr.transportstyrelsen.se/?ts-regnr-sok=' },
        ],
        ua: [
            { name: 'carplates.app', base: 'https://ua.carplates.app/en/number/' },
            { name: 'baza-gai.com.ua', base: 'https://baza-gai.com.ua/nomer/' },
            { name: 'auto-inform.com.ua', base: 'https://auto-inform.com.ua/search/' },
        ],
        uk: [
            { name: 'checkcardetails.co.uk', base: 'https://www.checkcardetails.co.uk/cardetails/' },
            { name: 'totalcarcheck.co.uk', base: 'https://totalcarcheck.co.uk/FreeCheck?regno=' },
            { name: 'checkhistory.co.uk', base: 'https://checkhistory.uk/vehicle/' },
        ],
        dk: [
            { name: 'digitalservicebog.dk', base: 'https://app.digitalservicebog.dk/search?country=dk&Registration=' },
            { name: 'esyn.dk', base: 'https://findsynsrapport.esyn.dk/result?registration=' },
        ],
        no: [{ name: 'vegvesen.no', base: 'https://www.vegvesen.no/en/vehicles/buy-and-sell/vehicle-information/check-vehicle-information/?registreringsnummer=' }],
        fr: [
            { name: 'immatriculation-auto.info', base: 'https://immatriculation-auto.info/vehicle/' },
            { name: 'carter-cash.com', base: 'https://www.carter-cash.com/?plate=', needsHyphen: true },
        ],
        es: [
            { name: 'carter-cash.es', base: 'https://www.carter-cash.es/piezas-auto/?plate=' },
        ],
        fi: [{ name: 'motonet.fi (API)', base: 'https://www.motonet.fi/api/vehicleInfo/registrationNumber/FI?locale=fi&registrationNumber=' }],
        cz: [{ name: 'uniqa.cz', base: 'https://www.uniqa.cz/online/pojisteni-vozidla/#ecvId=' }],
    };

    const url = window.location.href;
    const is = (code) => url.includes(`platesmania.com/${code}/add`);
    const supportedCodes = ['nl','ua','no','dk','fr','uk','fi','pl','lt','cz','se','es'];

    // --- Helpers ---
    function isLookupSiteAvailable() {
        return supportedCodes.some(is);
    }

    function selectedText(id) {
        const el = document.getElementById(id);
        if (!el || !el.options || el.selectedIndex < 0) return '';
        return el.options[el.selectedIndex].text;
    }

    function areFieldsFilled() {
        if (is('nl')) return document.getElementById('nomer').value !== '';
        if (is('ua')) {
            const region = document.getElementById('region1').value;
            const digits = document.getElementById('digit1').value;
            return region !== '' && digits !== '';
        }
        if (is('no') || is('dk') || is('se'))
            return document.getElementById('let').value !== '' && document.getElementById('digit').value !== '';
        if (is('fr')) {
            const b1 = document.getElementById('b1').value;
            const d2 = document.getElementById('digit2').value;
            const b2 = document.getElementById('b2').value;
            return b1 !== '' && d2 !== '' && b2 !== '';
        }
        if (is('es')) {
            const ctype = document.getElementById('ctype')?.value;
            if (!ctype) return false;
            if (ctype === '1') {
                return document.getElementById('digit1').value !== '' && document.getElementById('let').value !== '';
            }
            if (ctype === '2') {
                return selectedText('dip') !== '' && selectedText('region') !== '' && document.getElementById('digit1').value !== '';
            }
            if (ctype === '3') {
                return selectedText('region') !== '' && document.getElementById('digit1').value !== '' && document.getElementById('let').value !== '';
            }
            if (ctype === '4') {
                return selectedText('region') !== '' && document.getElementById('digit2').value !== '' && document.getElementById('let').value !== '';
            }
            if (ctype === '5') {
                return selectedText('region') !== '' && document.getElementById('digit1').value !== '' && document.getElementById('let').value !== '';
            }
            if (ctype === '7') {
                return selectedText('region') !== '' && document.getElementById('digit2').value !== '';
            }
            return false;
        }
        if (is('de') || is('ch')) return document.getElementById('digit').value !== '';
        if (is('pl') || is('uk')) return document.getElementById('nomerpl').value !== '';
        if (is('fi')) return document.getElementById('digit').value !== '';
        if (is('lt')) return document.getElementById('digit2').value !== '';
        if (is('cz')) {
            const d1 = document.getElementById('digit1').value;
            const d2 = document.getElementById('digit2').value;
            const d3 = document.getElementById('digit3').value;
            const nomer = document.getElementById('nomer').value;
            return d1 !== '' || d2 !== '' || d3 !== '' || nomer !== '';
        }
        return false;
    }

    function buildPlateForCurrentPage() {
        if (is('nl')) return document.getElementById('nomer').value;

        if (is('ua')) {
            const region = document.getElementById('region1').value;
            const digits = document.getElementById('digit1').value;
            const b1 = document.getElementById('b1').value;
            const b2 = document.getElementById('b2').value;
            return `${region}${digits}${b1}${b2}`;
        }

        if (is('no') || is('dk') || is('se')) {
            const letField = document.getElementById('let').value;
            const digitField = document.getElementById('digit').value;
            return `${letField}${digitField}`;
        }

        if (is('fr')) {
            const b1 = document.getElementById('b1').value;
            const digit2 = document.getElementById('digit2').value;
            const b2 = document.getElementById('b2').value;
            return `${b1}${digit2}${b2}`;
        }

        if (is('es')) {
            const ctype = document.getElementById('ctype')?.value;
            const q = (id) => document.getElementById(id)?.value || '';
            if (ctype === '1') {
                return q('digit1') + q('let');
            }
            if (ctype === '2') {
                return selectedText('dip') + selectedText('region') + q('digit1');
            }
            if (ctype === '3') {
                return selectedText('region') + q('digit1') + q('let');
            }
            if (ctype === '4') {
                return selectedText('region') + q('digit2') + q('let');
            }
            if (ctype === '5') {
                return selectedText('region') + q('digit1') + q('let');
            }
            if (ctype === '7') {
                return selectedText('region') + q('digit2');
            }
            return '';
        }

        if (is('fi')) {
            const letField = document.getElementById('let1').value;
            const digitField = document.getElementById('digit').value;
            return `${letField}-${digitField}`;
        }

        if (is('uk')) {
            return document.getElementById('nomerpl').value;
        }

        if (is('pl')) {
            const regionField = document.getElementById('region');
            const selectedRegionText = regionField.options[regionField.selectedIndex].text;
            const digitField = document.getElementById('nomerpl').value;
            return `${selectedRegionText}${digitField}`;
        }

        if (is('lt')) {
            const b1 = document.getElementById('b1');
            const b2 = document.getElementById('b2');
            const b3 = document.getElementById('b3');
            const d1 = document.getElementById('digit1');
            const d2 = document.getElementById('digit2');
            const d3 = document.getElementById('digit3');
            const vanity = document.getElementById('nomer');
            const ctype = document.getElementById('ctype').value;
            if (ctype === '1') return b1.value + b2.value + b3.value + d2.value;
            if (ctype === '2') return d1.value + b1.value + b2.value;
            if (ctype === '3') return b1.value + b2.value + d2.value;
            if (ctype === '4') return d1.value + b1.value + b2.value + b3.value;
            if (['5','6','7','9'].includes(ctype)) return vanity.value;
            if (ctype === '8') return d3.value + b1.value + b2.value;
            return '';
        }

        if (is('cz')) {
            const q = (id) => document.getElementById(id)?.value || '';
            const category = q('ctype');
            const regionField = document.getElementById('region');
            const selectedRegionText = regionField.options[regionField.selectedIndex].text;
            const b1 = q('b1'), b2 = q('b2'), b3 = q('b3');
            const d1 = q('digit1'), d2 = q('digit2'), d3 = q('digit3');
            const nomer = q('nomer'), el = q('el');

            switch (category) {
                case '1': return `${b1}${selectedRegionText}${b2}${d1}`;
                case '2': return `${b1}${selectedRegionText}${d1}`;
                case '4': return `${selectedRegionText}${b2}${d1}`;
                case '5': return `${selectedRegionText}${b2}${d1}`;
                case '6': return `${selectedRegionText}${b2}${d1}`;
                case '7': return `${selectedRegionText}${b2}${d2}`;
                case '8': return `${selectedRegionText}${b2}${d2}`;
                case '9': return `${selectedRegionText}${b2}${d2}`;
                case '10': return `${selectedRegionText}${b2}${d2}`;
                case '11': return nomer;
                case '3': return nomer;
                case '12': return `${el}${b3}${d3}`;
                case '13': return `${d1}${d3}`;
                default: return '';
            }
        }

        return '';
    }

    // For Google Images button we historically insert spaces between chunks on some countries.
    function buildPlateForSearchDisplay() {
        if (is('nl')) return document.getElementById('nomer').value;
        if (is('ua')) {
            const region = document.getElementById('region1').value;
            const digits = document.getElementById('digit1').value;
            const b1 = document.getElementById('b1').value;
            const b2 = document.getElementById('b2').value;
            return `${region} ${digits} ${b1}${b2}`;
        }
        if (is('no') || is('dk') || is('se')) {
            return document.getElementById('let').value + ' ' + document.getElementById('digit').value;
        }
        if (is('fr')) {
            const b1 = document.getElementById('b1').value;
            const d2 = document.getElementById('digit2').value;
            const b2 = document.getElementById('b2').value;
            return `${b1} ${d2} ${b2}`;
        }
        if (is('es')) {
            return buildPlateForCurrentPage();
        }
        if (is('de')) {
            const regionField = document.getElementById('region').value;
            const letField = document.getElementById('b1').value;
            const letField2 = document.getElementById('b2').value;
            const digitField = document.getElementById('digit').value;
            return `${regionField} ${letField} ${digitField}${letField2}`;
        }
        if (is('ch')) {
            const regionField = document.getElementById('region').value;
            const digitField = document.getElementById('digit').value;
            return `${regionField} ${digitField}`;
        }
        if (is('fi')) {
            return document.getElementById('let1').value + '-' + document.getElementById('digit').value;
        }
        if (is('pl')) {
            const regionField = document.getElementById('region');
            const selectedRegionText = regionField.options[regionField.selectedIndex].text;
            const digitField = document.getElementById('nomerpl').value;
            return selectedRegionText + ' ' + digitField;
        }
        if (is('uk')) {
            return document.getElementById('nomerpl').value;
        }
        if (is('lt') || is('cz')) {
            return buildPlateForCurrentPage();
        }
        return '';
    }

    function frWithHyphens(s) {
        return s.replace(/^([A-Z]{2})(\d{3})([A-Z]{2})$/i, '$1-$2-$3');
    }

    function onlyYearFromDate(s) {
        if (!s) return '';
        const m = String(s).match(/(\d{4})/);
        return m ? m[1] : '';
    }

    function showFIWindow(info) {
        const existing = document.getElementById('fiFloatWin');
        if (existing) existing.remove();

        const wrap = document.createElement('div');
        wrap.id = 'fiFloatWin';
        wrap.style.position = 'fixed';
        wrap.style.top = '80px';
        wrap.style.right = '40px';
        wrap.style.zIndex = '99999';
        wrap.style.background = '#fff';
        wrap.style.border = '1px solid #ccc';
        wrap.style.borderRadius = '6px';
        wrap.style.boxShadow = '0 6px 18px rgba(0,0,0,0.18)';
        wrap.style.minWidth = '260px';
        wrap.style.maxWidth = '420px';
        wrap.style.fontFamily = 'system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif';

        const header = document.createElement('div');
        header.style.padding = '10px 12px';
        header.style.borderBottom = '1px solid #eee';
        header.style.display = 'flex';
        header.style.alignItems = 'center';
        header.style.justifyContent = 'space-between';
        header.style.background = '#f8f9fa';

        const makeModel = `${info.manufacturerName || ''} ${info.model || ''}`.trim().replace(/\s+/g, ' ');
        const makeModelSpanHTML =
              `<span style="border-bottom: 1px dotted;" onclick="$('#markamodtype').val('${escAttr(makeModel)}').autocomplete('search', '${escAttr(makeModel)}'); return false;">${escHtml(makeModel)}</span>`;
        const y = onlyYearFromDate(info.registrationDate);
        const title = document.createElement('div');
        title.innerHTML = `${makeModelSpanHTML}${y ? ` (${escHtml(y)})` : ''}`;
        title.style.fontWeight = '600';

        const close = document.createElement('div');
        close.textContent = '×';
        close.title = 'Close';
        close.style.cursor = 'pointer';
        close.style.fontSize = '18px';
        close.style.lineHeight = '18px';
        close.style.marginLeft = '10px';
        close.onclick = () => wrap.remove();

        header.appendChild(title);
        header.appendChild(close);

        const body = document.createElement('div');
        body.style.padding = '10px 12px';
        body.style.fontSize = '14px';

        const rows = [
            ['Manufacturer', info.manufacturerName],
            ['Model', info.model],
            ['Type', info.type],
            ['VIN', info.VIN],
            ['Registration date', info.registrationDate],
            ['Fuel', info.fuel],
            ['Power', (info.powerKw || info.powerHp) ? `${info.powerKw ?? ''}${info.powerKw ? ' kW' : ''}${(info.powerKw && info.powerHp) ? ' / ' : ''}${info.powerHp ?? ''}${info.powerHp ? ' hp' : ''}` : ''],
        ].filter(([, v]) => v);

        for (const [label, value] of rows) {
            const row = document.createElement('div');
            row.style.display = 'flex';
            row.style.alignItems = 'center';
            row.style.margin = '6px 0';

            const text = document.createElement('div');
            text.textContent = `${label}: ${value}`;
            text.style.flex = '1 1 auto';

            const img = document.createElement('img');
            img.src = 'https://i.imgur.com/RjmoRpu.png';
            img.alt = 'Copy';
            img.title = 'Copy';
            img.style.height = '1em';
            img.style.cursor = 'pointer';
            img.style.marginLeft = '8px';
            img.onclick = () => copyToClipboard(String(value));

            row.appendChild(text);
            row.appendChild(img);
            body.appendChild(row);
        }

        wrap.appendChild(header);
        wrap.appendChild(body);
        document.body.appendChild(wrap);
        makeDraggable(wrap, header);
    }

    async function fetchMotonetData(fiPlateRaw) {
        const plate = String(fiPlateRaw || '').trim().toUpperCase();
        if (!plate) throw new Error('Empty plate');
        const url = `https://www.motonet.fi/api/vehicleInfo/registrationNumber/FI?locale=fi&registrationNumber=${encodeURIComponent(plate)}`;
        // Reuse httpGet from your script:
        const data = await httpGet(url).catch(() => ({}));
        return data && typeof data === 'object' ? data : {};
    }


    // --- Utils for RDW API + Floating Window ---
    function httpGet(url) {
        return new Promise((resolve, reject) => {
            if (typeof GM_xmlhttpRequest === 'function') {
                GM_xmlhttpRequest({
                    method: 'GET',
                    url,
                    headers: { 'Accept': 'application/json' },
                    onload: (res) => {
                        try { resolve(JSON.parse(res.responseText)); }
                        catch (e) { reject(e); }
                    },
                    onerror: (e) => reject(e),
                });
            } else {
                fetch(url).then(r => r.json()).then(resolve).catch(reject);
            }
        });
    }

    function onlyYear(yyyymmdd) {
        if (!yyyymmdd || typeof yyyymmdd !== 'string') return 'unknown';
        if (/^\d{8}$/.test(yyyymmdd)) return yyyymmdd.slice(0,4);
        return 'unknown';
    }

    function copyToClipboard(text) {
        const doFallback = () => {
            const ta = document.createElement('textarea');
            ta.value = text;
            document.body.appendChild(ta);
            ta.select();
            try { document.execCommand('copy'); } catch {}
            document.body.removeChild(ta);
        };
        if (navigator.clipboard && navigator.clipboard.writeText) {
            navigator.clipboard.writeText(text).catch(doFallback);
        } else {
            doFallback();
        }
    }

    function escHtml(s) {
        return String(s).replace(/[&<>"']/g, (c) => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
    }
    function escAttr(s) {
        return String(s).replace(/['"]/g, (c) => ({ "'": "\\'", '"': '\\"' }[c]));
    }

    function makeDraggable(win, handle) {
        let ox=0, oy=0, dragging=false;
        handle.style.cursor = 'move';
        handle.addEventListener('mousedown', (e) => {
            dragging = true;
            ox = e.clientX - win.offsetLeft;
            oy = e.clientY - win.offsetTop;
            document.addEventListener('mousemove', move);
            document.addEventListener('mouseup', up);
            e.preventDefault();
        });
        function move(e) {
            if (!dragging) return;
            win.style.left = (e.clientX - ox) + 'px';
            win.style.top = (e.clientY - oy) + 'px';
        }
        function up() {
            dragging = false;
            document.removeEventListener('mousemove', move);
            document.removeEventListener('mouseup', up);
        }
    }

    function showRDWWindow(info) {
        // info: { make, model, variant, yFirst, yNL, fuel, doors, color }
        const existing = document.getElementById('rdwFloatWin');
        if (existing) existing.remove();

        const wrap = document.createElement('div');
        wrap.id = 'rdwFloatWin';
        wrap.style.position = 'fixed';
        wrap.style.top = '80px';
        wrap.style.right = '40px';
        wrap.style.zIndex = '99999';
        wrap.style.background = '#fff';
        wrap.style.border = '1px solid #ccc';
        wrap.style.borderRadius = '6px';
        wrap.style.boxShadow = '0 6px 18px rgba(0,0,0,0.18)';
        wrap.style.minWidth = '260px';
        wrap.style.maxWidth = '380px';
        wrap.style.fontFamily = 'system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif';

        const header = document.createElement('div');
        header.style.padding = '10px 12px';
        header.style.borderBottom = '1px solid #eee';
        header.style.display = 'flex';
        header.style.alignItems = 'center';
        header.style.justifyContent = 'space-between';
        header.style.background = '#f8f9fa';

        const makeModel = `${info.make} ${info.model}`.trim().replace(/\s+/g,' ');
        const makeModelSpanHTML =
              `<span style="border-bottom: 1px dotted;" onclick="$('#markamodtype').val('${escAttr(makeModel)}').autocomplete('search', '${escAttr(makeModel)}'); return false;">${escHtml(makeModel)}</span>`;
        const y = info.yFirst && info.yFirst !== 'unknown' ? ` (${escHtml(info.yFirst)})` : '';
        const title = document.createElement('div');
        title.innerHTML = `${makeModelSpanHTML}${y}`;
        title.style.fontWeight = '600';

        const close = document.createElement('div');
        close.textContent = '×';
        close.title = 'Close';
        close.style.cursor = 'pointer';
        close.style.fontSize = '18px';
        close.style.lineHeight = '18px';
        close.style.marginLeft = '10px';
        close.onclick = () => wrap.remove();

        header.appendChild(title);
        header.appendChild(close);

        const body = document.createElement('div');
        body.style.padding = '10px 12px';
        body.style.fontSize = '14px';

        const rows = [
            ['Make', info.make],
            ['Model', info.model],
            ['Variant', info.variant],
            ['First registration', info.yFirst],
            ['First registration in NL', info.yNL],
            ['Fuel', info.fuel],
            ['Doors', info.doors],
            ['Color', info.color],
        ];

        for (const [label, value] of rows) {
            const row = document.createElement('div');
            row.style.display = 'flex';
            row.style.alignItems = 'center';
            row.style.margin = '6px 0';

            const text = document.createElement('div');
            text.textContent = `${label}: ${value}`;
            text.style.flex = '1 1 auto';

            const img = document.createElement('img');
            img.src = 'https://i.imgur.com/RjmoRpu.png';
            img.alt = 'Copy';
            img.title = 'Copy';
            img.style.height = '1em';
            img.style.cursor = 'pointer';
            img.style.marginLeft = '8px';
            img.onclick = () => copyToClipboard(String(value));

            row.appendChild(text);
            row.appendChild(img);
            body.appendChild(row);
        }

        wrap.appendChild(header);
        wrap.appendChild(body);
        document.body.appendChild(wrap);
        makeDraggable(wrap, header);
    }

    async function fetchRDWData(kentekenRaw) {
        const plate = String(kentekenRaw || '').trim().replace(/[\s-]+/g, '').toUpperCase();
        if (!plate) throw new Error('Empty plate');

        const baseUrl = 'https://opendata.rdw.nl/resource/m9d7-ebf2.json';
        const fuelUrl = 'https://opendata.rdw.nl/resource/8ys7-d773.json';
        const qBase = `${baseUrl}?kenteken=${encodeURIComponent(plate)}`;
        const qFuel = `${fuelUrl}?kenteken=${encodeURIComponent(plate)}`;

        const [base, fuel] = await Promise.all([
            httpGet(qBase).catch(() => []),
            httpGet(qFuel).catch(() => []),
        ]);

        const primary = Array.isArray(base) && base.length ? base[0] : {};
        const fuelTypes = (Array.isArray(fuel) ? fuel : [])
        .map(x => x.brandstof_omschrijving || x.brandstof_omschrijving_ || x.brandstof || '')
        .filter(Boolean);

        const info = {
            make: primary.merk || 'unknown',
            model: primary.handelsbenaming || 'unknown',
            variant: primary.variant || 'unknown',
            yFirst: onlyYear(primary.datum_eerste_toelating),
            yNL: onlyYear(primary.datum_eerste_tenaamstelling_in_nederland),
            fuel: fuelTypes.length ? fuelTypes.join('/') : 'unknown',
            doors: primary.aantal_deuren || 'unknown',
            color: primary.eerste_kleur || 'unknown',
        };

        return info;
    }

    // --- UI Button Factory (now supports optional left icon) ---
    function makeBtn(label, disabled, onclick, iconUrl) {
        const btn = document.createElement('button');
        btn.disabled = !!disabled;
        btn.style.marginBottom = '0';
        btn.style.width = '100%';
        btn.style.backgroundColor = disabled ? '#95a5a6' : '#3498db';
        btn.style.color = '#ffffff';
        btn.style.border = 'none';
        btn.style.cursor = disabled ? 'default' : 'pointer';
        btn.style.height = '23px';
        btn.style.borderRadius = '4px';
        btn.style.display = 'flex';
        btn.style.alignItems = 'center';
        btn.style.justifyContent = 'center';
        btn.style.gap = '6px';
        btn.style.padding = '0 8px';

        if (iconUrl) {
            const img = document.createElement('img');
            img.src = iconUrl;
            img.alt = '';
            img.style.maxHeight = (23 - 2) + 'px';
            img.style.display = 'inline-block';
            img.style.verticalAlign = 'middle';
            btn.appendChild(img);
        }

        const span = document.createElement('span');
        span.innerText = label;
        btn.appendChild(span);

        if (onclick && !disabled) btn.onclick = onclick;
        return btn;
    }

    // --- Buttons (Lookup / Google Images / Autogespot) ---
    function createOrUpdateLookupButtons() {
        const host = document.getElementById('zoomimgid');
        if (!host) return;

        let container = document.getElementById('lookupButtonsContainer');
        if (!isLookupSiteAvailable()) {
            if (container) container.remove();
            return;
        }
        if (!container) {
            container = document.createElement('div');
            container.id = 'lookupButtonsContainer';
            container.style.display = 'grid';
            container.style.gap = '6px';
            host.parentNode.insertBefore(container, host);
        } else {
            container.innerHTML = '';
        }

        const label = document.createElement('div');
        label.textContent = '(Ctrl+Click buttons to open in background)';
        label.style.fontSize = '9px';
        label.style.fontWeight = 'bold';
        label.style.marginBottom = '2px';
        label.style.textAlign = 'center'
        container.appendChild(label);

        const fieldsOk = areFieldsFilled();
        const code = supportedCodes.find(is);
        const sites = lookupSites[code] || [];

        // Countries with special flows
        const specialPL = is('pl');
        const specialLT = is('lt');

        if (specialPL) {
            const btn = makeBtn('Lookup', !fieldsOk, () => {
                const plateNumber = buildPlateForCurrentPage();
                const targetUrl =
                      `https://moj.gov.pl/nforms/engine/ng/index?nfWidReset=true&xFormsAppName=NormaEuro&xFormsOrigin=EXTERNAL&plateNumber=${encodeURIComponent(plateNumber)}#/search`;
                window.open(targetUrl, '_blank');
            });
            container.appendChild(btn);
            return;
        }

        if (specialLT) {
            const btn = makeBtn('Lookup', !fieldsOk, () => {
                const plateNumber = buildPlateForCurrentPage();
                let form = document.createElement('form');
                form.action = 'https://www.cab.lt/draustumo-patikra/';
                form.method = 'POST';
                form.target = '_blank';
                let inputCountry = document.createElement('input');
                inputCountry.type = 'hidden'; inputCountry.name = 'country'; inputCountry.value = 'LT';
                let inputPlate = document.createElement('input');
                inputPlate.type = 'hidden'; inputPlate.name = 'plate'; inputPlate.value = plateNumber;
                form.appendChild(inputCountry); form.appendChild(inputPlate);
                document.body.appendChild(form); form.submit(); document.body.removeChild(form);
            });
            container.appendChild(btn);
            return;
        }

        // Standard flow
        if (!sites.length) return;

        if (sites.length === 1) {
            const only = sites[0];
            const btn = makeBtn('Lookup', !fieldsOk, () => {
                const raw = buildPlateForCurrentPage();
                if (!raw) return;
                const finalPlate =
                      (is('fr') && only.needsHyphen) ? frWithHyphens(raw) : raw;
                window.open(only.base + finalPlate, '_blank');
            });
            container.appendChild(btn);
        } else {
            for (const site of sites) {
                const btn = makeBtn(site.name, !fieldsOk, () => {
                    const raw = buildPlateForCurrentPage();
                    if (!raw) return;
                    const finalPlate =
                          (is('fr') && site.needsHyphen) ? frWithHyphens(raw) : raw;
                    window.open(site.base + finalPlate, '_blank');
                });
                container.appendChild(btn);
            }
        }

        // --- NL: RDW API lookup button that opens floating window ---
        if (is('nl')) {
            const rdwBtn = makeBtn('RDW (API)', !fieldsOk, async () => {
                const plate = buildPlateForCurrentPage();
                if (!plate) return;
                // Visual feedback
                rdwBtn.disabled = true;
                rdwBtn.style.opacity = '0.7';
                try {
                    const info = await fetchRDWData(plate);
                    showRDWWindow(info);
                } catch (e) {
                    showRDWWindow({
                        make: 'unknown',
                        model: 'unknown',
                        variant: 'unknown',
                        yFirst: 'unknown',
                        yNL: 'unknown',
                        fuel: 'unknown',
                        doors: 'unknown',
                        color: 'unknown',
                    });
                } finally {
                    rdwBtn.disabled = false;
                    rdwBtn.style.opacity = '1';
                }
            });
            container.appendChild(rdwBtn);
        }

        // --- FI: Motonet API lookup button that opens floating window ---
        if (is('fi')) {
            const fiBtn = makeBtn('Motonet (API)', !fieldsOk, async () => {
                const plate = buildPlateForCurrentPage(); // returns "AAA-123"
                if (!plate) return;
                fiBtn.disabled = true;
                fiBtn.style.opacity = '0.7';
                try {
                    const info = await fetchMotonetData(plate);
                    showFIWindow(info && Object.keys(info).length ? info : {});
                } catch (e) {
                    showFIWindow({});
                } finally {
                    fiBtn.disabled = false;
                    fiBtn.style.opacity = '1';
                }
            });
            container.appendChild(fiBtn);
        }

    }

    function createOrUpdateGoogleImagesButton() {
        const host = document.getElementById('zoomimgid');
        if (!host) return;

        let googleBtn = document.getElementById('googleImagesButton');
        if (!googleBtn) {
            googleBtn = makeBtn('Google Images (search plate)', true, null, 'https://i.imgur.com/5x00UaD.png');
            googleBtn.id = 'googleImagesButton';
            const container = document.getElementById('lookupButtonsContainer');
            if (container) {
                container.appendChild(googleBtn);
            } else {
                host.parentNode.insertBefore(googleBtn, host);
            }

        }

        const fieldsOk = areFieldsFilled();
        googleBtn.disabled = !fieldsOk;
        googleBtn.onclick = !fieldsOk ? null : function () {
            const plateNumber = buildPlateForSearchDisplay();
            if (!plateNumber) return;
            window.open('https://www.google.com/search?tbm=isch&q="' + plateNumber + '"', '_blank');
        };
    }

    function createOrUpdateAutogespotButton() {
        const host = document.getElementById('zoomimgid');
        if (!host) return;

        let agBtn = document.getElementById('autogespotButton');
        if (!agBtn) {
            agBtn = makeBtn('Search on Autogespot', true, null, 'https://i.imgur.com/X8HxriW.png');
            agBtn.id = 'autogespotButton';
            const container = document.getElementById('lookupButtonsContainer');
            if (container) {
                container.appendChild(agBtn);
            } else {
                host.parentNode.insertBefore(agBtn, host);
            }
        }

        const fieldsOk = areFieldsFilled();
        agBtn.disabled = !fieldsOk;
        agBtn.style.marginBottom = '6px';
        agBtn.onclick = !fieldsOk ? null : function () {
            let plateCompact = buildPlateForCurrentPage();
            if (!plateCompact) {
                const display = buildPlateForSearchDisplay();
                plateCompact = (display || '').replace(/\s+/g, '');
            }
            if (!plateCompact) return;
            const target = `https://www.autogespot.com/spots?licenseplate=${encodeURIComponent(plateCompact)}`;
            window.open(target, '_blank');
        };
    }

    // --- Initial render + live updates ---
    function render() {
        createOrUpdateLookupButtons();
        createOrUpdateGoogleImagesButton();
        createOrUpdateAutogespotButton();
    }

    render();
    setInterval(render, 1000);
})();