eBay UI Enhancer (Price Stats + Item Page Charts)

Enhance eBay with dark mode, compact view, delivery toggles, ad blocking, seller badges, keyword filters, and now local price tracking with change stats and item-page mini-charts. Built by Eliminater74.

À partir de 2025-06-03. Voir la dernière version.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name         eBay UI Enhancer (Price Stats + Item Page Charts)
// @namespace    https://greatest.deepsurf.us/users/Eliminater74
// @version      3.5
// @description  Enhance eBay with dark mode, compact view, delivery toggles, ad blocking, seller badges, keyword filters, and now local price tracking with change stats and item-page mini-charts. Built by Eliminater74.
// @author       Eliminater74
// @license      MIT
// @match        https://www.ebay.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    const SETTINGS_KEY = 'ebayEnhancerSettings';
    const PRICE_CACHE_KEY = 'ebayPriceCache';

    const defaultSettings = {
        darkMode: false,
        compactView: false,
        showDelivery: true,
        showUnitPrice: true,
        hideAds: true,
        highlightTopSellers: true,
        keywordFilter: true,
        showPriceStats: true
    };

    let settings = JSON.parse(localStorage.getItem(SETTINGS_KEY)) || defaultSettings;
    let priceCache = JSON.parse(localStorage.getItem(PRICE_CACHE_KEY) || '{}');

    const gear = document.createElement('div');
    gear.innerHTML = '⚙️';
    gear.id = 'ebay-enhancer-gear';
    gear.title = 'eBay Enhancer Settings';
    gear.style.left = '20px';
    gear.style.top = '20px';
    document.body.appendChild(gear);

    const panel = document.createElement('div');
    panel.id = 'ebay-enhancer-panel';
    panel.innerHTML = `
        <label><input type="checkbox" id="darkModeToggle"> Dark Mode</label><br>
        <label><input type="checkbox" id="compactToggle"> Compact View</label><br>
        <label><input type="checkbox" id="deliveryToggle"> Show Delivery Info</label><br>
        <label><input type="checkbox" id="unitPriceToggle"> Show Unit Price</label><br>
        <label><input type="checkbox" id="hideAdsToggle"> Hide Sponsored Items</label><br>
        <label><input type="checkbox" id="highlightSellersToggle"> Highlight Top Rated Sellers</label><br>
        <label><input type="checkbox" id="keywordFilterToggle"> Filter by Keywords</label><br>
        <label><input type="checkbox" id="priceStatsToggle"> Show Price Change Stats</label>
    `;
    document.body.appendChild(panel);

    panel.querySelectorAll('input[type="checkbox"]').forEach(input => {
        const id = input.id;
        const key = id.replace('Toggle', '');
        input.checked = settings[key];
        input.addEventListener('change', () => {
            settings[key] = input.checked;
            localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings));
            applyEnhancements();
        });
    });

    gear.addEventListener('click', () => {
        panel.style.display = panel.style.display === 'block' ? 'none' : 'block';
    });

    function applyEnhancements() {
        document.body.classList.toggle('ebay-dark-mode', settings.darkMode);
        document.body.classList.toggle('ebay-compact-mode', settings.compactView);

        if (settings.hideAds) {
            document.querySelectorAll('[data-testid="spnAd"], [aria-label="Sponsored"]').forEach(ad => ad.remove());
        }

        if (settings.highlightTopSellers) {
            document.querySelectorAll('.s-item__etrs-text, .s-item__etrs-badge').forEach(el => {
                el.style.backgroundColor = '#d4f7d4';
                el.style.borderRadius = '4px';
                el.style.padding = '2px 4px';
            });
        }

        if (settings.keywordFilter) {
            const blocked = ['broken', 'damaged', 'for parts'];
            document.querySelectorAll('.s-item').forEach(item => {
                const txt = item.innerText.toLowerCase();
                if (blocked.some(term => txt.includes(term))) {
                    item.style.display = 'none';
                }
            });
        }

        if (settings.showPriceStats) {
            document.querySelectorAll('.s-item').forEach(item => {
                const title = item.querySelector('.s-item__title')?.innerText.trim();
                const priceEl = item.querySelector('.s-item__price');
                if (!title || !priceEl) return;

                const priceText = priceEl.innerText.replace(/[^\d.]/g, '').trim();
                const currentPrice = parseFloat(priceText);
                if (isNaN(currentPrice)) return;

                const key = title.toLowerCase();
                const history = priceCache[key] || [];
                const prev = history.at(-1);

                let change = '';
                if (prev && prev !== currentPrice) {
                    const diff = currentPrice - prev;
                    const pct = ((diff / prev) * 100).toFixed(1);
                    change = `<span style="color:${diff < 0 ? 'green' : 'red'}; font-size: 12px;">(${diff < 0 ? '▼' : '▲'} $${Math.abs(diff).toFixed(2)} / ${Math.abs(pct)}%)</span>`;
                }

                priceEl.innerHTML += ` <span class="price-change-tag">${change}</span>`;
                if (!Array.isArray(history)) priceCache[key] = [];
                if (priceCache[key].at(-1) !== currentPrice) {
                    priceCache[key].push(currentPrice);
                    if (priceCache[key].length > 10) priceCache[key].shift();
                }
            });
            localStorage.setItem(PRICE_CACHE_KEY, JSON.stringify(priceCache));
        }

        // Handle product page separately
        if (document.querySelector('#itemTitle')) {
            const itemTitle = document.querySelector('#itemTitle')?.innerText.replace(/^Details about\s*/, '').trim();
            const priceEl = document.querySelector('#prcIsum, .x-price-approx__price');
            if (itemTitle && priceEl) {
                const priceText = priceEl.innerText.replace(/[^\d.]/g, '').trim();
                const currentPrice = parseFloat(priceText);
                const key = itemTitle.toLowerCase();
                if (!isNaN(currentPrice)) {
                    const history = priceCache[key] || [];
                    const last = history.at(-1);
                    let chart = '';
                    if (history.length > 1) {
                        const min = Math.min(...history);
                        const max = Math.max(...history);
                        const scale = n => Math.round(((n - min) / (max - min)) * 7);
                        const bars = ['▁','▂','▃','▄','▅','▆','▇','█'];
                        chart = history.map(p => bars[scale(p)]).join('');
                    }
                    const statsBox = document.createElement('div');
                    statsBox.innerHTML = `<div style="margin-top:6px;font-size:13px;">Price History: ${chart || '—'}<br><strong>Last Seen:</strong> $${last ?? '—'}<br><strong>Now:</strong> $${currentPrice}</div>`;
                    priceEl.parentElement.appendChild(statsBox);
                    if (!Array.isArray(history)) priceCache[key] = [];
                    if (priceCache[key].at(-1) !== currentPrice) {
                        priceCache[key].push(currentPrice);
                        if (priceCache[key].length > 10) priceCache[key].shift();
                    }
                    localStorage.setItem(PRICE_CACHE_KEY, JSON.stringify(priceCache));
                }
            }
        }
    }

    applyEnhancements();

    const style = document.createElement('style');
    style.textContent = `
        #ebay-enhancer-gear {
            position: fixed;
            font-size: 24px;
            background: #333;
            color: white;
            padding: 6px 10px;
            border-radius: 50%;
            cursor: pointer;
            z-index: 99999;
        }
        #ebay-enhancer-panel {
            position: fixed;
            left: 20px;
            top: 60px;
            background: #fff;
            color: #000;
            padding: 10px;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0,0,0,0.3);
            display: none;
            z-index: 99999;
        }
        body.ebay-dark-mode {
            background-color: #1e1e1e !important;
            color: #ddd !important;
        }
        body.ebay-dark-mode a { color: #4ea3ff !important; }
        body.ebay-compact-mode .s-item {
            padding: 6px !important;
            font-size: 14px !important;
        }
        .price-change-tag {
            margin-left: 4px;
            font-weight: bold;
        }
    `;
    document.head.appendChild(style);
})();