// ==UserScript== // @name eBay Shipping Cost Calculator // @namespace http://tampermonkey.net/ // @version 1.8 // @description Adds shipping cost to item price in eBay search results // @author none // @match https://www.ebay.com/sch/* // @icon https://www.ebay.com/favicon.ico // @grant none // @downloadURL https://update.greasyfork.icu/scripts/513999/eBay%20Shipping%20Cost%20Calculator.user.js // @updateURL https://update.greasyfork.icu/scripts/513999/eBay%20Shipping%20Cost%20Calculator.meta.js // ==/UserScript== (function() { 'use strict'; let processing = false; let debounceTimer; // --- Settings --- let settings = { taxRate: parseFloat(localStorage.getItem('ebayTaxRate')) || 0, color: localStorage.getItem('ebayTotalColor') || '#e42648', fontSize: localStorage.getItem('ebayTotalFontSize') || '18' }; // --- Settings UI --- function createSettingsButton() { const button = document.createElement('div'); button.id = 'ebay-settings-button'; button.style.position = 'fixed'; button.style.top = '10px'; button.style.right = '10px'; button.style.width = '20px'; button.style.height = '20px'; button.style.borderRadius = '50%'; button.style.backgroundColor = '#e42648'; button.style.cursor = 'pointer'; button.style.zIndex = '10000'; button.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)'; document.body.appendChild(button); button.addEventListener('click', toggleSettingsWindow); } function createSettingsWindow() { const settingsDiv = document.createElement('div'); settingsDiv.id = 'ebay-shipping-settings'; settingsDiv.style.position = 'fixed'; settingsDiv.style.top = '40px'; settingsDiv.style.right = '20px'; settingsDiv.style.zIndex = '2147483647'; settingsDiv.style.background = 'white'; settingsDiv.style.border = '1px solid #ccc'; settingsDiv.style.padding = '16px'; settingsDiv.style.borderRadius = '8px'; settingsDiv.style.boxShadow = '0 2px 8px rgba(0,0,0,0.15)'; settingsDiv.style.fontFamily = 'Arial, sans-serif'; settingsDiv.style.minWidth = '220px'; settingsDiv.style.display = 'none'; document.addEventListener('click', function(event) { const settingsDiv = document.getElementById('ebay-shipping-settings'); const settingsButton = document.getElementById('ebay-settings-button'); if (settingsDiv && settingsDiv.style.display === 'block') { // Check if click is outside both settings window and button if (!settingsDiv.contains(event.target) && !settingsButton.contains(event.target)) { settingsDiv.style.display = 'none'; } } }); settingsDiv.innerHTML = ` Shipping Calculator Settings





`; document.body.appendChild(settingsDiv); // Event listeners document.getElementById('ebay-tax-rate').addEventListener('input', function() { settings.taxRate = parseFloat(this.value) || 0; localStorage.setItem('ebayTaxRate', settings.taxRate); addShippingToPrices(); // Always update on input }); document.getElementById('ebay-total-color').addEventListener('input', function() { settings.color = this.value; localStorage.setItem('ebayTotalColor', settings.color); addShippingToPrices(); }); document.getElementById('ebay-total-fontsize').addEventListener('input', function() { settings.fontSize = this.value; localStorage.setItem('ebayTotalFontSize', settings.fontSize); document.getElementById('ebay-total-fontsize-value').textContent = `${settings.fontSize}px`; addShippingToPrices(); }); } function toggleSettingsWindow() { const settingsDiv = document.getElementById('ebay-shipping-settings'); if (settingsDiv) { settingsDiv.style.display = settingsDiv.style.display === 'none' ? 'block' : 'none'; } } // --- Main logic --- function addShippingToPrices() { if (processing) return; processing = true; // Remove processed class to force recalculation on all items document.querySelectorAll('.s-card__attribute-row.processed').forEach(row => { row.classList.remove('processed'); }); // For each price row document.querySelectorAll('.s-card__attribute-row:not(.processed)').forEach(priceRow => { const priceEl = priceRow.querySelector('.s-card__price'); if (!priceEl) return; // Look ahead for a shipping row with 'delivery' let nextRow = priceRow.nextElementSibling; let shippingEl = null; while (nextRow) { if (nextRow.classList.contains('s-card__attribute-row')) { shippingEl = Array.from(nextRow.querySelectorAll('span')).find( el => el.textContent.toLowerCase().includes('delivery') ); if (shippingEl) break; } nextRow = nextRow.nextElementSibling; } if (!shippingEl) return; const price = parsePrice(priceEl.textContent); const shipping = parseShipping(shippingEl.textContent); if (price !== null && shipping !== null) { let total = price + shipping; if (settings.taxRate > 0) { total += total * (settings.taxRate / 100); } // Insert or update total display after priceEl let totalEl = priceRow.querySelector('.s-item__total'); if (!totalEl) { totalEl = document.createElement('div'); totalEl.className = 's-item__total'; priceEl.parentNode.insertBefore(totalEl, priceEl.nextSibling); } totalEl.textContent = `Total: $${total.toFixed(2)}`; totalEl.style.color = settings.color; totalEl.style.fontWeight = 'bold'; totalEl.style.fontSize = settings.fontSize + 'px'; } priceRow.classList.add('processed'); }); // Update already processed items in case settings changed document.querySelectorAll('.s-card__attribute-row.processed .s-item__total').forEach(totalEl => { totalEl.style.color = settings.color; totalEl.style.fontWeight = 'bold'; totalEl.style.fontSize = settings.fontSize + 'px'; }); processing = false; } function parsePrice(text) { const match = text.match(/\$([\d,.]+)/); if (!match) return null; return parseFloat(match[1].replace(/,/g, '')); } function parseShipping(text) { if (/free/i.test(text)) return 0; // Match $xx.xx before 'delivery' (with or without extra text after) const match = text.match(/\$([\d,.]+)\s+delivery/i); if (match) return parseFloat(match[1].replace(/,/g, '')); // Fallback: match any $xx.xx in the string const fallback = text.match(/\$([\d,.]+)/); if (fallback) return parseFloat(fallback[1].replace(/,/g, '')); return null; } function handleMutations() { clearTimeout(debounceTimer); debounceTimer = setTimeout(addShippingToPrices, 300); } // --- Init --- createSettingsButton(); createSettingsWindow(); addShippingToPrices(); const container = document.querySelector('.srp-river-main'); if (container) { const observer = new MutationObserver(handleMutations); observer.observe(container, { childList: true, subtree: false, attributes: false, characterData: false }); } })();