Greasy Fork is available in English.

Solotodo Limpiar Referidos Plox

Limpia enlaces redirigidos y elimina parámetros de seguimiento en solotodo.cl

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Solotodo Limpiar Referidos Plox
// @namespace    limpiotodo
// @version      0.2
// @description  Limpia enlaces redirigidos y elimina parámetros de seguimiento en solotodo.cl
// @author       Alplox
// @match        https://*.solotodo.cl/*
// @match        https://solotodo.cl/*
// @grant        none
// ==/UserScript==

(function () {
  'use strict';

  function safeDecode(s) {
    if (!s) return s;
    try { return decodeURIComponent(s); } catch (e) { return s; }
  }

  // Extrae URL destino caso: ad.soicos
  function extractFromAdSoicos(href) {
    if (!href) return null;
    try {
      const url = new URL(href);
      if (!/(^|\.)ad\.soicos\.com$/.test(url.hostname)) return null;
      const dl = url.searchParams.get('dl');
      if (dl) return safeDecode(dl);
      // patrón fallback: buscar primera apariencia de https%3A...
      const m = href.match(/https?:%2F%2F[^"&]+/i);
      if (m) return safeDecode(m[0]);
    } catch (e) { return null; }
    return null;
  }

  // Extrae URL destino caso: publicapi.solotodo.com/entities/meli_redirect/
  function extractFromMeliRedirect(href) {
    if (!href) return null;
    try {
      const url = new URL(href, location.href);
      if (!url.hostname.includes('publicapi.solotodo.com')) return null;
      if (!url.pathname.includes('meli_redirect')) return null;
      const target = url.searchParams.get('url');
      if (target) return safeDecode(target);
      // patrón fallback: buscar primera apariencia de https%3A...
      const m = href.match(/https?:%2F%2F[^"&]+/i);
      if (m) return safeDecode(m[0]);
    } catch (e) { return null; }
    return null;
  }

  // Extrae la URL destino de redirecciones conocidas
  function extractTarget(href) {
    if (!href) return null;
    const tryMeli = extractFromMeliRedirect(href);
    if (tryMeli) return tryMeli;
    const tryAd = extractFromAdSoicos(href);
    if (tryAd) return tryAd;
    return null;
  }

  function cleanUrl(u) {
    if (!u) return u;
    // Quitar comillas si existen
    u = u.trim().replace(/^["']|["']$/g, '');

    // Crear objeto URL para manipulación
    try {
      const url = new URL(u, location.href);

      // Eliminar parámetros de seguimiento comunes
      const trackingParams = [
        'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',
        'gclid', 'fbclid', 'ref', 'referrer', 'kid', 'aff', 'affiliate',
        'tracking', 'click_id', 'source', 'cid', 'sid', 'utm_id'
      ];

      trackingParams.forEach(param => {
        url.searchParams.delete(param);
      });

      // Asegurar uso de HTTPS si no se especifica protocolo
      if (!url.protocol) url.protocol = 'https:';

      return url.toString();
    } catch (e) {
      // Si URL no es válida, retornar como está pero forzar HTTPS
      return u.startsWith('http') ? u : 'https://' + u;
    }
  }

  function processLink(a) {
    if (!(a instanceof HTMLAnchorElement)) return;
    const original = a.getAttribute('href');
    if (!original) return;

    // Intentar extraer URL destino si es redirección conocida
    const target = extractTarget(original);
    const finalUrl = target ? cleanUrl(target) : cleanUrl(original);

    // Actualizar href si ha cambiado
    if (finalUrl !== original) {
      a.setAttribute('href', finalUrl);
    }

    // Eliminar atributos de seguimiento comunes
    ['data-tracking', 'data-ref', 'data-referrer', 'onclick', 'onmousedown', 'data-cid'].forEach(attr => {
      try { a.removeAttribute(attr); } catch (e) {}
    });

    // Asegurar seguridad con rel="noopener"
    a.setAttribute('rel', 'noopener');
  }

  function processAll(root = document) {
    const selector = [
      'a[href*="ad.soicos"]',
      'a[href*="publicapi.solotodo.com"][href*="meli_redirect"]',
      'a[href*="meli_redirect"]',
      'a[href*="utm_"]',
      'a[href*="kid="]',
      'a[href*="affiliate"]'
    ].join(',');
    const links = root.querySelectorAll(selector);
    links.forEach(processLink);
  }

  // Configurar MutationObserver para detectar cambios dinámicos
  const observer = new MutationObserver((mutations) => {
    for (const m of mutations) {
      if (m.addedNodes && m.addedNodes.length) {
        m.addedNodes.forEach(node => {
          if (node.nodeType !== 1) return;
          if (node.matches && node.matches('a')) processLink(node);
          if (node.querySelectorAll) processAll(node);
        });
      }
      if (m.type === 'attributes' && m.target && m.target.matches && m.target.matches('a')) {
        processLink(m.target);
      }
    }
  });

  // Procesar todos los enlaces inicialmente
  processAll();

  // Iniciar observador
  observer.observe(document.documentElement || document.body, {
    childList: true,
    subtree: true,
    attributes: true,
    attributeFilter: ['href']
  });

  // Reintentos periódicos para asegurar limpieza en contenido dinámico (o por si acaso sitio carga lento)
  let tries = 0;
  const retry = setInterval(() => {
    processAll();
    if (++tries > 8) clearInterval(retry);
  }, 800);
})();