Advertisement
Mike0xlong

AMAZON SEARCH++

Mar 23rd, 2025
455
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.05 KB | Source Code | 0 0
  1. // ==UserScript==
  2. // @name         Amazon Filter: Must Contain & Exclude + OOS + Clean URL
  3. // @namespace    http://tampermonkey.net/
  4. // @version      1.7
  5. // @description  Single UI for "must contain" and "exclude" words, hide out-of-stock, and copy clean Amazon URL. Auto-refilters on page updates.
  6. // @match        https://www.amazon.ca/*
  7. // @grant        GM_setClipboard
  8. // ==/UserScript==
  9.  
  10. (function() {
  11.     'use strict';
  12.  
  13.     // Arrays to hold filter words:
  14.     //  - mustContainWords: user wants these words in the product title
  15.     //  - excludeWords: user wants to exclude these words from the product title
  16.     let mustContainWords = [];
  17.     let excludeWords = [];
  18.  
  19.     // Reference to the "hide out-of-stock" checkbox
  20.     let hideOOSCheckbox = null;
  21.  
  22.     // --------------------------- COPY CLEAN URL ------------------------------
  23.     function copyCleanAmazonURL() {
  24.         const currentURL = window.location.href;
  25.         // Regex to extract a base URL like: https://www.amazon.ca/.../dp/ABC123XYZ
  26.         const match = currentURL.match(/(https:\/\/www\.amazon\.ca\/.*?\/dp\/[A-Z0-9]+\/?)/);
  27.         if (match) {
  28.             const cleanURL = match[1];
  29.             if (typeof GM_setClipboard === 'function') {
  30.                 GM_setClipboard(cleanURL, 'text');
  31.             } else {
  32.                 // Fallback if GM_setClipboard isn't available
  33.                 navigator.clipboard.writeText(cleanURL)
  34.                     .catch(err => console.error('Clipboard write failed:', err));
  35.             }
  36.             alert(`Copied cleaned URL to clipboard: ${cleanURL}`);
  37.         } else {
  38.             alert('No clean Amazon URL could be extracted on this page.');
  39.         }
  40.     }
  41.  
  42.     // ----------------------- CREATE SINGLE UI PANEL --------------------------
  43.     function createUI() {
  44.         // Main container, fixed at bottom-right
  45.         const uiContainer = document.createElement('div');
  46.         uiContainer.style.position = 'fixed';
  47.         uiContainer.style.bottom = '10px';
  48.         uiContainer.style.right = '10px';
  49.         uiContainer.style.zIndex = '9999';
  50.         uiContainer.style.backgroundColor = '#fff';
  51.         uiContainer.style.padding = '10px';
  52.         uiContainer.style.border = '1px solid #ccc';
  53.         uiContainer.style.borderRadius = '5px';
  54.         uiContainer.style.boxShadow = '0 0 10px rgba(0,0,0,0.1)';
  55.         uiContainer.style.maxWidth = '300px';
  56.         uiContainer.style.fontFamily = 'sans-serif';
  57.  
  58.         // Title
  59.         const uiTitle = document.createElement('div');
  60.         uiTitle.innerText = 'Amazon Filter & URL Tool';
  61.         uiTitle.style.fontWeight = 'bold';
  62.         uiTitle.style.marginBottom = '5px';
  63.         uiContainer.appendChild(uiTitle);
  64.  
  65.         // This div will list all (MC) and excluded words
  66.         const wordsList = document.createElement('div');
  67.         wordsList.style.marginBottom = '10px';
  68.         updateWordsList(wordsList);
  69.         uiContainer.appendChild(wordsList);
  70.  
  71.         // Row for "Must Contain" input + button
  72.         const mustContainRow = document.createElement('div');
  73.         mustContainRow.style.marginBottom = '10px';
  74.  
  75.         const mustContainLabel = document.createElement('div');
  76.         mustContainLabel.innerText = 'Must Contain:';
  77.         mustContainLabel.style.fontWeight = 'bold';
  78.         mustContainLabel.style.marginBottom = '3px';
  79.         mustContainRow.appendChild(mustContainLabel);
  80.  
  81.         const mustContainInput = document.createElement('input');
  82.         mustContainInput.type = 'text';
  83.         mustContainInput.placeholder = 'Enter words required';
  84.         mustContainInput.style.padding = '5px';
  85.         mustContainInput.style.width = '100%';
  86.         mustContainRow.appendChild(mustContainInput);
  87.  
  88.         const mustContainButton = document.createElement('button');
  89.         mustContainButton.innerText = 'Add Must-Contain';
  90.         mustContainButton.style.marginTop = '5px';
  91.         mustContainButton.style.width = '100%';
  92.         mustContainButton.style.padding = '5px 10px';
  93.         mustContainButton.style.cursor = 'pointer';
  94.         mustContainRow.appendChild(mustContainButton);
  95.  
  96.         mustContainButton.addEventListener('click', () => {
  97.             const newWord = mustContainInput.value.trim().toLowerCase();
  98.             if (newWord && !mustContainWords.includes(newWord)) {
  99.                 mustContainWords.push(newWord);
  100.                 mustContainInput.value = '';
  101.                 updateWordsList(wordsList);
  102.             }
  103.             filterProducts();
  104.         });
  105.  
  106.         uiContainer.appendChild(mustContainRow);
  107.  
  108.         // Row for "Exclude" input + button
  109.         const excludeRow = document.createElement('div');
  110.         excludeRow.style.marginBottom = '10px';
  111.  
  112.         const excludeLabel = document.createElement('div');
  113.         excludeLabel.innerText = 'Exclude (Forbidden Words):';
  114.         excludeLabel.style.fontWeight = 'bold';
  115.         excludeLabel.style.marginBottom = '3px';
  116.         excludeRow.appendChild(excludeLabel);
  117.  
  118.         const excludeInput = document.createElement('input');
  119.         excludeInput.type = 'text';
  120.         excludeInput.placeholder = 'Enter words to exclude';
  121.         excludeInput.style.padding = '5px';
  122.         excludeInput.style.width = '100%';
  123.         excludeRow.appendChild(excludeInput);
  124.  
  125.         const excludeButton = document.createElement('button');
  126.         excludeButton.innerText = 'Add Exclude';
  127.         excludeButton.style.marginTop = '5px';
  128.         excludeButton.style.width = '100%';
  129.         excludeButton.style.padding = '5px 10px';
  130.         excludeButton.style.cursor = 'pointer';
  131.         excludeRow.appendChild(excludeButton);
  132.  
  133.         excludeButton.addEventListener('click', () => {
  134.             const newWord = excludeInput.value.trim().toLowerCase();
  135.             if (newWord && !excludeWords.includes(newWord)) {
  136.                 excludeWords.push(newWord);
  137.                 excludeInput.value = '';
  138.                 updateWordsList(wordsList);
  139.             }
  140.             filterProducts();
  141.         });
  142.  
  143.         uiContainer.appendChild(excludeRow);
  144.  
  145.         // Row with the "Hide OOS" checkbox
  146.         const hideOOSRow = document.createElement('div');
  147.         hideOOSRow.style.display = 'flex';
  148.         hideOOSRow.style.alignItems = 'center';
  149.         hideOOSRow.style.marginBottom = '10px';
  150.  
  151.         hideOOSCheckbox = document.createElement('input');
  152.         hideOOSCheckbox.type = 'checkbox';
  153.         hideOOSCheckbox.style.marginRight = '5px';
  154.         hideOOSRow.appendChild(hideOOSCheckbox);
  155.  
  156.         const hideOOSLabel = document.createElement('label');
  157.         hideOOSLabel.innerText = 'Hide out-of-stock items';
  158.         hideOOSRow.appendChild(hideOOSLabel);
  159.  
  160.         // When toggled, re-filter
  161.         hideOOSCheckbox.addEventListener('change', () => {
  162.             filterProducts();
  163.         });
  164.  
  165.         uiContainer.appendChild(hideOOSRow);
  166.  
  167.         // "Copy Clean URL" button
  168.         const copyURLButton = document.createElement('button');
  169.         copyURLButton.innerText = 'Copy Clean URL';
  170.         copyURLButton.style.width = '100%';
  171.         copyURLButton.style.padding = '5px 10px';
  172.         copyURLButton.style.cursor = 'pointer';
  173.  
  174.         copyURLButton.addEventListener('click', () => {
  175.             copyCleanAmazonURL();
  176.         });
  177.         uiContainer.appendChild(copyURLButton);
  178.  
  179.         // Finally, add this panel to the page
  180.         document.body.appendChild(uiContainer);
  181.     }
  182.  
  183.     // ----------------------- UPDATE WORDS LIST DISPLAY -----------------------
  184.     function updateWordsList(container) {
  185.         container.innerHTML = '';
  186.  
  187.         // If we have mustContainWords, list them first
  188.         if (mustContainWords.length > 0) {
  189.             const mcTitle = document.createElement('div');
  190.             mcTitle.innerText = 'Must Contain:';
  191.             mcTitle.style.marginBottom = '3px';
  192.             mcTitle.style.fontWeight = 'bold';
  193.             container.appendChild(mcTitle);
  194.  
  195.             mustContainWords.forEach(word => {
  196.                 const row = document.createElement('div');
  197.                 row.style.display = 'flex';
  198.                 row.style.alignItems = 'center';
  199.                 row.style.marginBottom = '3px';
  200.  
  201.                 const wordLabel = document.createElement('span');
  202.                 wordLabel.innerText = `(MC) ${word}`;
  203.                 wordLabel.style.marginRight = '10px';
  204.                 row.appendChild(wordLabel);
  205.  
  206.                 const removeBtn = document.createElement('span');
  207.                 removeBtn.innerText = '❌';
  208.                 removeBtn.style.cursor = 'pointer';
  209.                 removeBtn.style.color = 'red';
  210.  
  211.                 removeBtn.addEventListener('click', () => {
  212.                     mustContainWords = mustContainWords.filter(w => w !== word);
  213.                     updateWordsList(container);
  214.                     filterProducts();
  215.                 });
  216.  
  217.                 row.appendChild(removeBtn);
  218.                 container.appendChild(row);
  219.             });
  220.  
  221.             // Add a small spacing
  222.             const sep = document.createElement('div');
  223.             sep.style.margin = '5px 0';
  224.             container.appendChild(sep);
  225.         }
  226.  
  227.         // Now excludeWords
  228.         if (excludeWords.length > 0) {
  229.             const exTitle = document.createElement('div');
  230.             exTitle.innerText = 'Excluded Words:';
  231.             exTitle.style.marginBottom = '3px';
  232.             exTitle.style.fontWeight = 'bold';
  233.             container.appendChild(exTitle);
  234.  
  235.             excludeWords.forEach(word => {
  236.                 const row = document.createElement('div');
  237.                 row.style.display = 'flex';
  238.                 row.style.alignItems = 'center';
  239.                 row.style.marginBottom = '3px';
  240.  
  241.                 const wordLabel = document.createElement('span');
  242.                 wordLabel.innerText = word;
  243.                 wordLabel.style.marginRight = '10px';
  244.                 row.appendChild(wordLabel);
  245.  
  246.                 const removeBtn = document.createElement('span');
  247.                 removeBtn.innerText = '❌';
  248.                 removeBtn.style.cursor = 'pointer';
  249.                 removeBtn.style.color = 'red';
  250.  
  251.                 removeBtn.addEventListener('click', () => {
  252.                     excludeWords = excludeWords.filter(w => w !== word);
  253.                     updateWordsList(container);
  254.                     filterProducts();
  255.                 });
  256.  
  257.                 row.appendChild(removeBtn);
  258.                 container.appendChild(row);
  259.             });
  260.         }
  261.     }
  262.  
  263.     // ----------------------- FILTER PRODUCTS LOGIC ---------------------------
  264.     function filterProducts() {
  265.         const products = document.querySelectorAll('.s-main-slot .s-result-item');
  266.         const hideOOS = hideOOSCheckbox && hideOOSCheckbox.checked;
  267.  
  268.         products.forEach(product => {
  269.             let shouldHide = false;
  270.  
  271.             // 1) Must Contain: if user added mustContainWords, we require
  272.             //    the product title to contain *all* of them, or we hide it
  273.             const titleEl = product.querySelector('h2');
  274.             if (titleEl) {
  275.                 const titleText = titleEl.innerText.toLowerCase();
  276.  
  277.                 // Must contain check
  278.                 if (mustContainWords.length > 0) {
  279.                     // The product must contain ALL mustContainWords
  280.                     for (const w of mustContainWords) {
  281.                         if (!titleText.includes(w)) {
  282.                             shouldHide = true;
  283.                             break;
  284.                         }
  285.                     }
  286.                 }
  287.  
  288.                 // Exclude check (only do it if not hidden yet)
  289.                 if (!shouldHide && excludeWords.length > 0) {
  290.                     for (const w of excludeWords) {
  291.                         if (titleText.includes(w)) {
  292.                             shouldHide = true;
  293.                             break;
  294.                         }
  295.                     }
  296.                 }
  297.             }
  298.  
  299.             // 2) If not hidden yet, check Hide Out-of-Stock
  300.             if (!shouldHide && hideOOS) {
  301.                 const productText = product.textContent.toLowerCase();
  302.                 if (productText.includes('no featured offers available')) {
  303.                     shouldHide = true;
  304.                 }
  305.             }
  306.  
  307.             // Finally show/hide
  308.             product.style.display = shouldHide ? 'none' : '';
  309.         });
  310.     }
  311.  
  312.     // -------------------- MUTATION OBSERVER FOR AUTO-REFILTER ----------------
  313.     function observeSearchResults() {
  314.         const mainSlot = document.querySelector('.s-main-slot');
  315.         if (!mainSlot) return;
  316.  
  317.         const observer = new MutationObserver(() => {
  318.             // Whenever the DOM changes in .s-main-slot, re-filter
  319.             filterProducts();
  320.         });
  321.  
  322.         observer.observe(mainSlot, {
  323.             childList: true,
  324.             subtree: true
  325.         });
  326.     }
  327.  
  328.     // ------------------------------ INIT -------------------------------------
  329.     window.addEventListener('load', () => {
  330.         createUI();
  331.         observeSearchResults();
  332.         filterProducts();  // Initial run
  333.     });
  334.  
  335. })();
  336.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement