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.7.2
// @description  Shows lookup buttons on Platesmania upload pages.
// @match        https://platesmania.com/*/add*
// @grant        GM_setValue
// @license      MIT
// @namespace    http://greasyfork.icu/users/976031
// ==/UserScript==

(function () {
  'use strict';

  const lookupSites = {
    nl: [
      { name: 'finnik.nl', base: 'https://finnik.nl/kenteken/' },
      { name: 'rdwdata.nl', base: 'https://www.rdwdata.nl/kenteken/' },
      { name: 'autoweek.nl', base: 'https://www.autoweek.nl/kentekencheck/' },
    ],
    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/pieces-auto/?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');
  }

  // --- 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 = '10px';
    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'; // button height minus 2
      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 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);
      }
    }
  }

  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';
      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';
      host.parentNode.insertBefore(agBtn, host);
    }

    const fieldsOk = areFieldsFilled();
    agBtn.disabled = !fieldsOk;
    agBtn.onclick = !fieldsOk ? null : function () {
      // Prefer the compact builder (no spaces) where available
      let plateCompact = buildPlateForCurrentPage();
      if (!plateCompact) {
        // Fall back to the search-display variant and just strip spaces
        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);
})();